• hdu6073[dfs+删边] 2017多校4


    题目中对二分图的定义十分特殊, 指的是 U,V两部分中,U的顶点度数必定为2,V中顶点无限制。

    题目要求的是 对于所有匹配,该匹配的权值=该匹配中选中的边的边权的乘积,求所有匹配权值之和。

    对于V中的顶点,a∈V , 如果a的度数为1, 那么a的最优匹配就已经决定了,此时将a对答案的贡献记录下来(ans乘上该边的权即可,因为任意一种匹配都必定包含此边)。

    删去a点后,所有与a相连的顶点度数-1,如果这个时候又出现了度数为1的顶点,就重复类似a的操作,直到图中再无度数为1的顶点。

    可以发现,这就是无向图判环的一种方法。剩下的顶点度数必定为2(题目中的特殊条件限制),且构成x个环。

    对于每个环我们可以发现

    都会只有两种取法使得最优匹配,这种跳着取边算贡献的过程我们可以用dfs实现。

    题目中,一种 最优匹配的权值 是 最优匹配中所有边的乘积,所以对于一个环,我们算出 Sum蓝色=蓝色边  Sum红色=红色边

    计算(Sum蓝色+Sum红色)与当前的ans相乘即可,因为任意 两个之间的最优匹配都可以随意配对 比如 环a红色配环b蓝色, 环a蓝色配 环b蓝色...

    /*hdu6073[dfs+删边] 2017多校4*/
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL MOD = 998244353LL;
    struct Edge {
        int to, cost;
        Edge(int T = 0, int C = 0)
            : to(T), cost(C) {}
    };
    vector<Edge>G[600005];
    int deg[600005];
    bool vis[600005];
    int T, n, u, v, w;
    LL x = 1, y = 1;
    LL res = 1, ans = 1;
    void init() {
        res = 1, ans = 1;
        for (int i = 0; i <= 2 * n; i++) {
            G[i].clear();
        }
        memset(deg, 0, sizeof(deg));
        memset(vis, 0, sizeof(vis));
    }
    void dfs(int u, int fa, int c) {
        if (vis[u]) return;
        vis[u] = 1;
        for (int i = 0; i < (int)G[u].size(); i++) {
            Edge &e = G[u][i];
            if (e.to == fa || deg[e.to] != 2) continue;
            dfs(e.to, u, c ^ 1);
            if (c) x = (x * e.cost) % MOD;
            else y = (y * e.cost) % MOD;
            break;
        }
        return;
    }
    void solve() {
        queue<int>q;
        for (int i = 1; i <= 2 * n; i++) {
            if (deg[i] == 1) {
                q.push(i);
            }
        }
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            deg[u]--;
            for (int i = 0; i < (int)G[u].size(); i++) {
                Edge &e = G[u][i];
                deg[e.to]--;
                if (!vis[e.to] && !vis[u]) {
                    vis[e.to] = vis[u] =  1;
                    res = (res * e.cost) % MOD;
                }
                if (deg[e.to] == 1) {
                    q.push(e.to);
                }
            }
        }
        memset(vis, 0, sizeof(vis));
        for (int i = 1; i <= 2 * n; i++) {
            if (deg[i] == 2 && !vis[i]) {
                x = 1, y = 1;
                dfs(i, i, 1);
                //cout << x << ' ' << y << endl;
                ans = (ans * (x + y)) % MOD;
            }
        }
        ans = (ans * res) % MOD;
        printf("%lld
    ", ans);
    }
    int main() {
        //freopen("1007.in", "r", stdin);
        //freopen("1007.txt", "w", stdout);
        scanf("%d", &T);
        while (T--) {
            scanf("%d", &n);
            init();
            for (int i = 1; i <= n; i++) {
                scanf("%d%d", &v, &w);
                G[i].push_back(Edge(v + n, w));
                G[v + n].push_back(Edge(i, w));
                deg[i]++, deg[v + n]++;
                scanf("%d%d", &v, &w);
                G[i].push_back(Edge(v + n, w));
                G[v + n].push_back(Edge(i, w));
                deg[i]++, deg[v + n]++;
            }
            solve();
        }
        return 0;
    }
     
  • 相关阅读:
    树线段hdu 4508 美素数(线段树)
    自定义context自定义Dialog之Progress(二)
    实现语言C语言简单实现五子棋
    调用博客paip.基于HTML gui界面的javascript JS实现SLEEP。。
    水印控件windows phone中,制作一个自定义的密码输入框控件,含图片,有水印,星号显示
    请求网络网络编程
    调试网页PAIP HTML的调试与分析工具
    输出流输入输入输出流
    标记协议http协议与XML书写规范及解析技术
    描述算法10673 Play with Floor and Ceil
  • 原文地址:https://www.cnblogs.com/UnderSilenceee/p/7286650.html
Copyright © 2020-2023  润新知