hdu6073 Matching In Multiplication

xiaoxiao2021-02-28  122

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

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

时间复杂度O(n)

#include<iostream> #include<stdio.h> #include<vector> using namespace std; typedef long long ll; const int maxn=6e5+10; const int mod=998244353; struct edge{ int v;ll w; }; int t,n,cnt,d[maxn],q[maxn]; bool vis[maxn]; ll ans,tmp[2]; vector<edge> e[maxn]; void dfs(int u,int flag,int f){ for(int i=0;i<e[u].size();i++){ int v=e[u][i].v; if(!vis[v]&&v!=f){ vis[v]=1; tmp[flag]=(tmp[flag]*e[u][i].w)%mod; dfs(v,flag^1,u); } } } int main(){ scanf("%d",&t); while(t--){ scanf("%d",&n); ans=1;cnt=0; for(int i=1;i<=2*n;i++) e[i].clear(),d[i]=0,vis[i]=0; for(int i=1;i<=n;i++){ int v1,v2;ll w1,w2; scanf("%d%lld%d%lld",&v1,&w1,&v2,&w2); e[i].push_back({v1+n,w1}); e[i].push_back({v2+n,w2}); e[v1+n].push_back({i,w1}); e[v2+n].push_back({i,w2}); d[i]+=2,d[v1+n]++,d[v2+n]++; } for(int i=n;i<=2*n;i++) if(d[i]==1) q[cnt++]=i,vis[i]=1; int cur=0; while(cur<cnt){ int u=q[cur++]; for(int i=0;i<e[u].size();i++){ int v=e[u][i].v; if(!vis[v]){ ans=(ans*e[u][i].w)%mod; vis[v]=1; for(int j=0;j<e[v].size();j++) if(--d[e[v][j].v]==1) q[cnt++]=e[v][j].v,vis[e[v][j].v]=1; } } } //printf("%d\n",ans); for(int i=1;i<=n;i++) if(!vis[i]) tmp[0]=tmp[1]=1,dfs(i,1,-1),ans=(ans*(tmp[0]+tmp[1]))%mod; printf("%lld\n",ans); } }

转载请注明原文地址: https://www.6miu.com/read-38516.html

最新回复(0)