HDU6073 Matching In Multiplication【拓扑】

来源:互联网 发布:网络女主播圈子很乱 编辑:程序博客网 时间:2024/06/06 11:01

题意:每个左边的点有两条边连到右边,一个完美匹配的权重等于匹配边的价值累乘,求权重和


思路:官方题解写的挺清楚的。

官方题解:首先如果一个点的度数为1,那么它的匹配方案是固定的,继而我们可以去掉这一对点。通过拓扑我们可以不断去掉所有度数为1的点。

那么剩下的图中左右各有m个点,每个点度数都不小于2,且左边每个点度数都是2,而右侧总度数是2m,因此右侧只能是每个点度数都是2。这说明这个图每个连通块是个环,在环上间隔着取即可,一共两种方案。


#include<stdio.h>#include<iostream>#include<string.h>#include<string>#include<stdlib.h>#include<math.h>#include<vector>#include<list>#include<map>#include<stack>#include<queue>#include<algorithm>#include<numeric>#include<functional>using namespace std;typedef long long ll;const int maxn = 6e5+5;const int MOD = 998244353;int n,d[maxn],vis[maxn];ll tot,ans;vector<int> v[maxn],w[maxn];void init(){memset(d,0,sizeof d);for(int i = 1; i <= 2*n; i++){v[i].clear();w[i].clear();}}void add(int x,int y,int val){v[x].push_back(y);w[x].push_back(val);d[x]++;v[y].push_back(x);w[y].push_back(val);d[y]++;}void topsort(){queue<int> q;while(!q.empty())q.pop();for(int i = 1; i <= 2*n; i++){if(d[i] == 1){d[i] = 0;q.push(i);}}while(!q.empty()){int x = q.front();q.pop();int y;for(int i = 0; i < v[x].size(); i++){if(d[ v[x][i] ]){tot = tot * w[x][i] % MOD;y = v[x][i];d[y] = 0;break;}}for(int i = 0; i < v[y].size(); i++){if(v[y][i] == x) continue;int tp = v[y][i];d[tp]--;if(d[tp] == 1){d[tp] = 0;q.push(tp);}}}}void dfs(int x,int t,ll a,ll b,int fa){int i;if(fa != -1)d[x] = 0;for(i = 0; i < v[x].size(); i++){if(d[ v[x][i] ] && v[x][i] != fa){if(t%2)a = a * w[x][i] % MOD;elseb = b * w[x][i] % MOD;break;}}if(i < v[x].size())dfs(v[x][i],t+1,a,b,x);elseans = ans * ( a + b)  % MOD;}int main(void){int T,i,j,k;scanf("%d",&T);while(T--){scanf("%d",&n);init();for(i = 1; i <= n; i++){int a,b,c,d;scanf("%d%d%d%d",&a,&b,&c,&d);add(i,a+n,b);add(i,c+n,d);}tot = 1ll;topsort();ans = tot;for(i = 1; i <= 2*n; i++){if(d[i] == 0) continue;dfs(i,1,1,1,-1);}printf("%lld\n",ans);}return 0;}


阅读全文
0 0