1. 程式人生 > >Codeforces 1093D. Beautiful Graph【二分圖染色】+【組合數】

Codeforces 1093D. Beautiful Graph【二分圖染色】+【組合數】

<題目連結>

題目大意:

給你一個無向圖(該無向圖無自環,且無重邊),現在要你給這個無向圖的點加權,所加權值可以是1,2,3。給這些點加權之後,要使得任意邊的兩個端點權值之和為奇數,問總共有多少種可能?結果mod 998244353。

解題分析:

整張圖的所有頂點賦權之後,一定分為奇、偶兩部分點集,並且,要想使的該圖滿足條件,任意邊的兩個端點的奇偶性應該是不同的,所以我們可以用DFS對圖進行二分圖染色,將圖分為兩個部分,需要注意的是,該圖未必連通。然後就是DFS的過程中,如果下一個點已經染過色,且顏色與當前點顏色相同,說明該圖不符合條件。將當前連通分量分成兩部分之後,也有兩種情況,一是:第一部分為奇數,因為奇數有1、3兩種選擇,所以情況有 2^cnt1 種 ;二是:第二部分是奇數,則情況有 2^cnt2 種。然後再將所有連通分量的情況相乘,就是最終得到的所有情況。

 1 #include <cstdio>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 #define rep(i,s,t) for(int i=s;i<=t;i++)
 7 typedef long long ll;
 8 const ll mod = 998244353;
 9 const int N =  3*1e5+10;
10 int n,m,cnt1,cnt2;
11 vector<int>G[N];
12 int color[N]; 13 ll ans,fact[N]; 14 bool fp; 15 16 void dfs(int u){ 17 if(color[u]==1)cnt1++; //1部分的個數 18 else cnt2++; //2部分的個數 19 for(int i=0;i<G[u].size();i++){ 20 int v=G[u][i]; 21 if(color[u]==color[v]){ fp=false; return ;} //如果染色時,發現相鄰兩點顏色相同,則出現衝突,說明該圖不符合條件
22 if(color[v])continue; 23 if(color[u]==1)color[v]=2; //將相鄰兩點分成不同部分 24 else if(color[u] == 2)color[v]=1; 25 dfs(v); 26 } 27 } 28 29 int main(){ 30 fact[0]=1;for(int i=1;i<N;i++)fact[i]=fact[i-1]*2%mod; 31 int T;scanf("%d",&T);while(T--){ 32 scanf("%d%d",&n,&m); 33 rep(i,0,n)G[i].clear(),color[i]=0; 34 rep(i,1,m){ 35 int u,v;scanf("%d%d",&u,&v); 36 G[u].push_back(v);G[v].push_back(u); 37 } 38 fp=true;ans=1; 39 rep(i,1,n) if(!color[i]){ 40 cnt1=cnt2=0; 41 color[i]=1;dfs(i); //將當前連通分量利用二分圖染色法分成1、2兩個不同的部分 42 if(!fp){ans=0;break;} 43 ans*=(ll)(fact[cnt1]+fact[cnt2]); //如果1的部分填奇數,因為每個奇數點都有兩種選擇,所以有fact[cnt1]種情況,如果2的部分填奇數,則有fact[cnt2]種情況 44 ans %= mod; 45 } 46 printf("%lld\n",ans%mod); 47 } 48 }

 

 

2018-12-30