HDU 6073 - Matching In Multiplication | 2017 Multi-University Training Contest 4
/* HDU 6073 - Matching In Multiplication [ 图论 ] | 2017 Multi-University Training Contest 4 题意: 定义一张二分图,U中每个节点和V中两个节点连边 完美匹配的权值为该匹配所有边的权值相乘 求所有完美匹配的权值之和 分析: 可以发现有些V中的点只能连唯一的U中的点 按拓扑排序思路将这些全部处理掉后,剩下的点构成一个个环 每个环有两种连线方式,间隔取边权 */ #include <bits/stdc++.h> using namespace std; #define LL long long const int N = 600005; const LL MOD = 998244353; struct Edge { int v; LL w; }; vector<Edge> G[N]; int vis[N]; int cnt[N]; int t, n; LL ans; queue<int> que; LL s[2]; void dfs(int x, int pre, int p) { if (vis[x]) return; vis[x] = 2; for (const auto & e : G[x]) { if (vis[e.v] == 1 || e.v == pre) continue; s[p] = s[p] * e.w % MOD; dfs(e.v, x, p^1); break; } } void solve() { for (int i = n+1; i <= 2*n; i++) if (G[i].size() == 1) que.push(i); ans = 1; while (!que.empty()) { int y = que.front(); que.pop(); vis[y] = 1; for (const auto& e: G[y]) { if (!vis[e.v]) { vis[e.v] = 1; ans = ans * e.w % MOD; for (const auto & ee: G[e.v]) { if (vis[ee.v]) continue; cnt[ee.v]--; if (cnt[ee.v] == 1) que.push(ee.v); } } } } for (int i = 1; i <= n; i++) { if (!vis[i]) { s[0] = s[1] = 1; dfs(i, i, 0); ans = ans * (s[0] + s[1]) % MOD; } } } void init(int n) { for (int i = 0; i <= n; i++) G[i].clear(); while (!que.empty()) que.pop(); memset(vis, 0, sizeof(vis)); memset(cnt, 0, sizeof(cnt)); } int main() { scanf("%d", &t); while (t--) { scanf("%d", &n); init(n<<1); for (int i = 1; i <= n; i++) { int v; LL w; scanf("%d%lld", &v, &w); v += n; G[i].push_back(Edge{v, w}); G[v].push_back(Edge{i, w}); cnt[v]++; scanf("%d%lld", &v, &w); v += n; G[i].push_back(Edge{v, w}); G[v].push_back(Edge{i, w}); cnt[v]++; } solve(); printf("%lld\n", ans); } }
我自倾杯,君且随意