HDU-2017 多校训练赛4-1007-Matching In Multiplication

来源:互联网 发布:哈尔滨商业大学知乎 编辑:程序博客网 时间:2024/06/07 03:13

ACM模版

描述

描述

题解

这是我做过的为数不多的二分图的问题中最有趣的一道了,首先确定的是左边的点和右边的点集数目是一样的,另外,我们确定左边的每个点向右边的点伸出两条路,那么,我们可以知悉,左边的点的度全部为 2,因为至少有一个完美匹配,所以右边的点度数全部大于等于 1。那么此时,我们可以首先对右边点的度数为 1 的进行删点,删边,还有对应连边的左边的点,为什么呢?因为当度数为 1 时,路径是固定的,我们可以直接去掉,只考虑路径不唯一的,所以左右两边各删除 x 个点,那么两边都剩下 y 个点,并且右边的度数全部大于 1,这时,因为我们知道左边的点的度数一定是 2y,右边当然也是,所以可以肯定右边所有点的度数也是 2,那么,很明显的是,只有两种方案,问题也就没什么了,差不多解决了。

给大家提供一下官方题解参考,大同小异:

描述

这个题必须赞一下,思维十分紧凑的一个题,好题!!!

代码

#include <cstdio>const int MAXN = 3e5 * 2 + 10;const int MOD = 998244353;int n, cnt;int q[MAXN];int hed[MAXN];int deg[MAXN];int v[MAXN << 1];int val[MAXN << 1];int nxt[MAXN << 1];bool vis[MAXN];inline void add(int x, int y, int z){    deg[x]++;    deg[y]++;    v[++cnt] = y;    val[cnt] = z;    nxt[cnt] = hed[x];    hed[x] = cnt;    v[++cnt] = x;    val[cnt] = z;    nxt[cnt] = hed[y];    hed[y] = cnt;}inline int go(int x){    for (int i = hed[x]; i; i = nxt[i])    {        if (!vis[v[i]])        {            return v[i];        }    }    return 0;}inline int get(int x, int y){    for (int i = hed[x]; i; i = nxt[i])    {        if (v[i] == y)        {            return val[i];        }    }    return 0;}void init(){    cnt = 0;    int x = n << 1;    for (int i = 1; i <= x; i++)    {        hed[i] = deg[i] = vis[i] = 0;    }}int main(){//    freopen("/Users/zyj/Desktop/input.txt", "r", stdin);    int T;    scanf("%d", &T);    while (T--)    {        scanf("%d", &n);        init();        int y, w;        for (int i = 1; i <= n; i++)    //  1 ~ n U n+1 ~ 2n V        {            scanf("%d%d", &y, &w);            add(i, y + n, w);            scanf("%d%d", &y, &w);            add(i, y + n, w);        }        n <<= 1;        int t = 0;        for (int i = (n >> 1) + 1; i <= n; i++)        {            if (deg[i] == 1)            {                q[++t] = i;            }        }        int ans = 1, h = 1;        while (h <= t)        {            int u = q[h++], w = 0;            for (int i = hed[u]; i; i = nxt[i])            {                if (!vis[v[i]])                {                    w = v[i];                    ans = 1LL * ans * val[i] % MOD;                    break;                }            }            vis[u] = vis[w] = 1;            for (int i = hed[w]; i; i = nxt[i])            {                u = v[i];                if (!vis[u])                {                    deg[u]--;                    if (deg[u] == 1)                    {                        q[++t] = u;                    }                }            }        }        for (int i = 1; i <= n; i++)        {            if (!vis[i])            {                vis[q[t = 1] = i] = 1;                for (int j = go(i); j; j = go(j))                {                    vis[q[++t] = j] = 1;                }                q[t + 1] = q[1];                y = w = 1;                for (int j = 1; j <= t; j += 2)                {                    y = 1LL * y * get(q[j], q[j + 1]) % MOD;                }                for (int j = 2; j <= t; j += 2)                {                    w = 1LL * w * get(q[j], q[j + 1]) % MOD;                }                ans = 1LL * ans * (y + w) % MOD;            }        }        printf("%d\n", ans);    }    return 0;}
原创粉丝点击