<题目链接>
题目大意:
给你一个无向图(该无向图无自环,且无重边),现在要你给这个无向图的点加权,所加权值可以是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
原文地址:https://www.cnblogs.com/00isok/p/10199276.html
时间: 2024-11-06 03:09:36