题意:有\(n\)个点,\(m\)条边的无向图,可以给每个点赋点权\({1,2,3}\),使得每个点连的奇偶不同,问有多少种方案,答案对\(998244353\)取模.
题解:要使得每个点所连的奇偶不同,很明显是二分图染色,那么对于某一个联通块,我们可以对左边的点赋\(2\),右边的点赋\({1,3}\),那么左边的点没有选择,只有一种情况,而右边的点每个点可以有两种情况,如果右边的点数是\(k2\),那么方案数就是\(2^k2\),如果左边赋\({1,3}\)且点数为\(k1\),右边赋\(2\),方案数就是\(2^k1\),所以一个联通块的方案数就是\(2^k1+2^k2\).我们可以不考虑点权,直接dfs二分图染色,记录二分图两边的点数,再直接贡献给答案即可.
代码:
int t;
int n,m;
vector<int> v[N];
int color[N];
int g[N];
int cnt[N];
int ans;
bool dfs(int x,int c){
color[x]=c;
for(auto w:v[x]){
if(!color[w]){
if(!dfs(w,3-c)) return false;
}
else{
if(color[w]==c) return false;
}
}
cnt[c]++;
return true;
}
int main() {
//ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
scanf("%d",&t);
g[0]=1;
for(int i=1;i<=300010;++i){
g[i]=g[i-1]*2%mod;
}
while(t--){
scanf("%d %d",&n,&m);
ans=1;
for(int i=1;i<=n;++i){
color[i]=0;
}
for(int i=1;i<=m;++i){
int a,b;
scanf("%d %d",&a,&b);
v[a].pb(b);
v[b].pb(a);
}
bool ok=true;
for(int i=1;i<=n;++i){
if(!color[i]){
cnt[1]=cnt[2]=0;
if(!dfs(i,1)){
ok=false;
break;
}
else{
ans=(ll)ans*(g[cnt[1]]+g[cnt[2]])%mod;
}
}
}
if(ok) printf("%d\n",ans);
else printf("0\n");
for(int i=1;i<=n;++i) v[i].clear();
}
return 0;
}
Educational Codeforces Round 56 (Rated for Div. 2) D. Beautiful Graph (二分图染色)
原文:https://www.cnblogs.com/lr599909928/p/13409151.html