4415. 点的赋值

题目链接

4415. 点的赋值

给定一个 \(n\) 个点 \(m\) 条边的无向无权图。

点的编号为 \(1∼n\)

图中不含重边和自环。

现在,请你给图中的每个点进行赋值,要求:

每个点的权值只能是 \(1\)\(2\)\(3\)
对于图中的每一条边,其两端点的权值之和都必须是奇数。
请问,共有多少种不同的赋值方法。

由于结果可能很大,你只需要输出对 \(998244353\) 取模后的结果。

输入格式

第一行包含整数 \(T\),表示共有 \(T\) 组测试数据。

每组数据第一行包含两个整数 \(n,m\)

接下来 \(m\) 行,每行包含两个整数 \(u,v\),表示点 \(u\) 和点 \(v\) 之间存在一条边。

输出格式

一个整数,表示不同赋值方法的数量对 \(998244353\) 取模后的结果。

解题思路

染色法判定二分图

很显然,任意一条路径要形成 \(奇数——偶数——奇数——……\) 这种情况,即将点分为奇数和偶数两部分,相当于对图进行染色,使得相邻两点颜色不同,即转换为二分图染色问题,由于可能不止一个连通块,如果存在一个连通块不能完成二分图染色则表示这样路径不存在,则方案数为 \(0\),否则对于每一个连通块,设两种颜色的数量分别为 \(cnt1,cnt2\)\(cnt1\) 表示为奇数数量时,每个点都有 \(1\)\(3\) 两种情况,\(cnt2\) 也可以表示为奇数数量,故一个连通块内有 \(2^{cnt1}+2^{cnt2}\) 种方案,另外,连通块之间的方案是互不影响的,利用乘法原理即得总方案数

  • 时间复杂度:\(O(n+m)\)

代码

// Problem: 点的赋值
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/4418/
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=3e5+5,mod=998244353;
int n,m,t,x,y,color[N],f[N],cnt1,cnt2;
vector<int> adj[N];
bool dfs(int x,int c)
{
	color[x]=c;
	if(c==1)cnt1++;
	else
		cnt2++;
	for(int y:adj[x])
		if(!color[y])
		{
			if(!dfs(y,3-c))return false;
		}
		else if(color[y]==c)return false;
	return true;
}
int main()
{
    help;
    f[0]=1;
    for(int i=1;i<N;i++)f[i]=1ll*2*f[i-1]%mod;
    for(cin>>t;t;t--)
    {
    	cin>>n>>m;
    	for(int i=1;i<=n;i++)adj[i].clear(),color[i]=0;
    	while(m--)
    	{
    		int x,y;
    		cin>>x>>y;
    		adj[x].pb(y),adj[y].pb(x);
    	}
    	int res=1;
    	for(int i=1;i<=n;i++)
    		if(!color[i])
    		{
    			cnt1=cnt2=0;
    			if(!dfs(i,1))
    			{
    				res=0;
    				break;
    			}
				res=1ll*res*(f[cnt1]+f[cnt2])%mod;
    		}
    	cout<<res<<'\n';
    }
    return 0;
}
posted @ 2022-04-30 20:28  zyy2001  阅读(57)  评论(0编辑  收藏  举报