zoukankan      html  css  js  c++  java
  • 晚间测试4 哪一天她能重回我身边 神奇建图+基环树

    题目描述




    分析

    对于 (20\%) 的数据,我们随便写个搜索就可以了
    对于 (100\%) 的数据,建图的方式很神奇
    我们从一张卡牌背面的数字向其正面的数字连边
    这样问题就转化为了翻转最少的边,使得所有点的入度不超过一
    为了方便处理,我们从正面向反面建一条权值为一的边,从反面向正面建一条权值为零的边
    这样在计算反转次数是只要加上边权就可以了
    首先我们要把图中所有的联通块预处理出来
    如果一些点想要形成联通块,那么边数一定大于等于 (n-1)
    而根据鸽巢原理,如果边数大于 (n),那么至少会有一个点的入度为 (2)
    所以只可能有两种情况
    1、联通块形成一棵树
    此时树中必定有且只有一个节点的入度为 (0)
    我们就可以枚举这一个入度为 (0) 的点是哪一个,然后进行树形 (DP)
    直接暴力枚举是不行的,可以换根
    2、联通块形成一个环
    此时该基环树一定是一个外向树(不在环上的点的连边的方向指向环外)
    环之外的点的方向一定是确定的
    那么我们只要枚举环上的点是逆时针还是顺时针即可

    代码

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define rg register
    inline int read() {
        rg int x = 0, fh = 1;
        rg char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-')
                fh = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            x = (x << 1) + (x << 3) + (ch ^ 48);
            ch = getchar();
        }
        return x * fh;
    }
    const int maxn = 2e5 + 5;
    const int mod = 998244353;
    int h[maxn], tot = 2;
    struct asd {
        int frm, to, nxt, val;
    } b[maxn];
    inline void ad(int aa, int bb, int cc) {
        b[tot].frm = aa;
        b[tot].to = bb;
        b[tot].val = cc;
        b[tot].nxt = h[aa];
        h[aa] = tot++;
    }
    int t, n, ds, bs, f[maxn], g[maxn], cnt, sum, sto, rt, nowcnt, nowsum, A, B, bjg, ansA, ansB, cnthuan;
    bool vis[maxn], huan[maxn], visA[maxn], visB[maxn];
    void qk() {
        memset(h, -1, sizeof(h));
        memset(b, 0, sizeof(b));
        tot = 2, sum = 1, cnt = 0, sto = 0;
        memset(vis, 0, sizeof(vis));
        memset(f, 0, sizeof(f));
        memset(g, 0, sizeof(g));
        memset(huan, 0, sizeof(huan));
        memset(visA, 0, sizeof(visA));
        memset(visB, 0, sizeof(visB));
    }
    void dfs(int now) {
        ds++;
        vis[now] = 1;
        for (rg int i = h[now]; i != -1; i = b[i].nxt) {
            rg int u = b[i].to;
            bs++;
            if (!vis[u])
                dfs(u);
        }
    }
    //找出联通块
    void dfs2(int now, int fa) {
        for (rg int i = h[now]; i != -1; i = b[i].nxt) {
            rg int u = b[i].to;
            if (u == fa)
                continue;
            dfs2(u, now);
            g[now] += g[u] + b[i].val;
        }
    }
    void dfs3(int now, int fa) {
        if (now == rt) {
            f[now] = g[now];
            if (f[now] < nowcnt) {
                nowcnt = f[now];
                nowsum = 1;
            } else if (f[now] == nowcnt) {
                nowsum++;
            }
        }
        for (rg int i = h[now]; i != -1; i = b[i].nxt) {
            rg int u = b[i].to;
            if (u == fa)
                continue;
            f[u] = f[now];
            if (b[i].val == 1)
                f[u]--;
            else
                f[u]++;
            if (f[u] < nowcnt) {
                nowcnt = f[u];
                nowsum = 1;
            } else if (f[u] == nowcnt) {
                bjg = i;
                nowsum++;
            }
            dfs3(u, now);
        }
    }
    //换根
    void findit(int now, int fa) {
        huan[now] = 1;
        cnthuan++;
        for (rg int i = h[now]; i != -1; i = b[i].nxt) {
            rg int u = b[i].to;
            if (u == fa)
                continue;
            if (!huan[u])
                findit(u, now);
            else {
                A = u, B = now, bjg = i;
            }
        }
    }
    //找环
    void hahaA(int now) {
        visA[now] = 1;
        for (rg int i = h[now]; i != -1; i = b[i].nxt) {
            rg int u = b[i].to;
            if (visA[u] || i == bjg || i == (bjg ^ 1))
                continue;
            ansA += b[i].val;
            hahaA(u);
        }
    }
    //顺时针跑一遍
    void hahaB(int now) {
        visB[now] = 1;
        for (rg int i = h[now]; i != -1; i = b[i].nxt) {
            rg int u = b[i].to;
            if (visB[u] || i == bjg || i == (bjg ^ 1))
                continue;
            ansB += b[i].val;
            hahaB(u);
        }
    }
    //逆时针跑一遍
    int main() {
        t = read();
        rg int aa, bb;
        while (t--) {
            qk();
            n = read();
            for (rg int i = 1; i <= n; i++) {
                aa = read(), bb = read();
                ad(aa, bb, 1), ad(bb, aa, 0);
            }
            for (rg int i = 1; i <= n * 2; i++) {
                if (!vis[i]) {
                    ds = 0, bs = 0;
                    dfs(i);
                    bs /= 2;
                    if (!bs)
                        continue;
                    if (bs > ds) {
                        sto = 1;
                        break;
                    } else if (ds == bs + 1) {
                        rt = i, nowcnt = 0x3f3f3f3f, nowsum = 0;
                        dfs2(i, 0), dfs3(i, 0);
                        cnt += nowcnt;
                        sum = 1LL * sum * nowsum % mod;
                    } else {
                        ansA = 0, ansB = 0, cnthuan = 0;
                        findit(i, 0);
                        if (cnthuan == 1) {
                            continue;
                        } else {
                            hahaA(A), hahaB(B);
                            if (b[bjg].val == 1)
                                ansA++;
                            else
                                ansB++;
                            if (ansA == ansB) {
                                cnt += ansA;
                                sum = sum * 2 % mod;
                            } else {
                                cnt += std::min(ansA, ansB);
                            }
                        }
                    }
                }
            }
            if (sto) {
                printf("-1 -1
    ");
            } else {
                printf("%d %d
    ", cnt, sum);
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    CentOS 安装Python3, pip3
    Pyinstaller打包python程序,以及遇到的问题:Cannot find existing PyQt5 plugin directories
    [Python] fetchone()和fetchall()
    在Linux命令行下,如何登录mysql server
    管理MySQL的客户端软件-MySQL Workbench
    在win10修改jupyter notebook(Anaconda安装)工作路径
    安装spark过程中出现Exception in thread "main" java.lang.UnsupportedClassVersionError错误的解决办法
    如何在win10本地主机操作系统和virtualBox 的Ubuntu之间设置共享文件夹
    支持向量机(SVM)
    特征工程(python)
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/13787235.html
Copyright © 2011-2022 走看看