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

xiaoxiao2021-02-28  93

ACM模版

描述

题解

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

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

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

代码

#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; }
转载请注明原文地址: https://www.6miu.com/read-38153.html

最新回复(0)