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

猜你喜欢

转载自www.cnblogs.com/00isok/p/10199276.html