1. 程式人生 > >CodeForces - 1093D:Beautiful Graph(二分圖判定+方案數)

CodeForces - 1093D:Beautiful Graph(二分圖判定+方案數)

題意:給定無向圖,讓你給點加權(1,2,3),使得每條邊是兩端點點權和維奇數。

思路:一個連通塊是個二分圖,判定二分圖可以dfs,並查集,2-sat染色。 這裡用的並查集(還可以帶權並查集優化一下,或者乾脆用dfs)。

計數的時候每個連通塊單獨考慮,我們從連通塊的第一個點開始dfs,如果是該填奇數點,那麼當前方案數*=2;分第一個點奇偶兩種情況即可。

(多組輸入一定注意初始化,這次CF多組輸入好坑啊。。。

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using
namespace std; const int maxn=2000010; const int Mod=998244353; int Laxt[maxn],Next[maxn],To[maxn],cnt,num1,num2,vis[maxn],tot,ans; void add(int u,int v){ Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; } void dfs(int u,int f,int x,int y) { tot++; vis[u]=1; if(x==1) num1=num1*2%Mod;
if(y==1) num2=num2*2%Mod; for(int i=Laxt[u];i;i=Next[i]){ if(To[i]!=f&&!vis[To[i]]) dfs(To[i],u,1-x,1-y); } } int fa[maxn]; int find(int x){ if(fa[x]==x) return x; return fa[x]=find(fa[x]); } int main() { int T,N,M,u,v; scanf("%d",&T);
while(T--){ scanf("%d%d",&N,&M); rep(i,1,N) Laxt[i]=0; cnt=0; rep(i,1,N+N) fa[i]=i,vis[i]=0; bool F=true; rep(i,1,M){ scanf("%d%d",&u,&v); add(u,v); add(v,u); if(find(u)==find(v)) F=false; fa[find(u)]=find(v+N); fa[find(v)]=find(u+N); } if(!F) puts("0"); else { ans=1; rep(i,1,N) { if(!vis[i]){ num1=1; num2=1; tot=0; dfs(i,0,0,1); if(tot==1) ans=3LL*ans%Mod; else ans=1LL*ans*(num1+num2)%Mod; } } printf("%d\n",ans); } } return 0; }