Problem-940D-Codeforces(dfs)

//好久没写博客了,最近脑子感觉非常不好使。个人认为写博客是提升总结的一个重要途径,于是我又回来了。

题意要求使每条边两端的顶点填上的值和为奇数,则很容易想到如果一端是奇数,则另一端只能是偶数,符合题意的构造方式必须是奇偶相间的。那么题目转化为检查题目中所给图是否为一个二分图,设将顶点集V分为的两个集合大小分别为cnt0,cnt1,那么该图的方案个数为2^{cnt0}+2^{cnt1}。因为可用的奇数有2个,偶数只有1个,所以大小为cnt0的顶点集合填奇数共有2^{cnt0}种,大小为cnt1的顶点集合填奇数共有2^{cnt1}种,相加即为所求。检查二分图可以采用黑白染色的方法,如果遇到相邻的点已被染成同一颜色即返回false。

坑点:

1.题目并未保证所给图连通,因此需要对每个连通子图分别计算结果,然后运用乘起来(乘法原理)

2.多测。数组,变量勿忘初始化

3.t高达3e5,如果你试图用memset初始化数组会超时。

#include<bits/stdc++.h>
using namespace std;

#define pb push_back
#define fi first
#define se second
#define ll long long
#define pq priority_queue
#define mp make_pair
#define pii pair<int,int>
#define mod 998244353
#define debug(x) cerr<<#x<<"="<<x<<'\n'

int lowbit(int x) {return x&(-x);}
int T;
int n,m;
vector <int> edge[300010];
int cnt0,cnt1;
ll ans;
int col[300010];
int power[300010];

bool bfs(int node,int c) {
	col[node]=c;
	if (c==0) cnt0++;
	else cnt1++;
	for (int i=0;i<edge[node].size();i++) {
		int v=edge[node][i];
		if (col[v]!=-1) {
			if (col[v]==c) return false;
		}
		else if (!bfs(v,1-c)) return false;
	}
	return true;
}

int add(int a,int b) {
	return (a+b)%mod;
}

void solve() {
	ans=1;
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) edge[i].clear();
	for (int i=0;i<m;i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		edge[u].pb(v);
		edge[v].pb(u);
	}
	for (int i=1;i<=n;i++) col[i]=-1;
	for (int i=1;i<=n&&ans!=0;i++) {
		cnt0=cnt1=0;
		if (col[i]!=-1) continue;
		if (!bfs(i,0)) ans=0;
		else ans=1ll*ans*add(power[cnt0],power[cnt1])%mod;
	}
	printf("%d\n",ans);
}

int main(){
	scanf("%d",&T);
	power[0]=1;
	for (int i=1;i<300010;i++) power[i]=power[i-1]*2ll%mod;
	while (T--) solve();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42158832/article/details/87524309