题目
思路
要求一条边所在的两个端点权值相加为奇数,则说明一条边两个端点,一个是奇数,一个是偶数(奇+偶=奇),除去这种情况,其他情况都不符合题意,所以这个只要判断这是否是个二分图就行。一个集合放奇数,一个集合放偶数。
假设放奇数的集合有x个数,放偶数的集合有y个数,因为奇数有两种选择,1和3,而偶数只有一种选择,2,所以种数就是(2^x) *(1^y ),因为奇数,偶数的个数可以倒过来,所以就是(2^x *1^y) + (2^y * 1^x) ,就是2^x + 2^y .又因为不保证图里只有一个连通块,所以最终答案就是每个连通块的答案的乘积,如果某个连通块不是二分图,答案就是0
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
const int inf=0x3f3f3f3f;
const int mod=998244353;
typedef long long ll;
typedef pair<int,int> PII;
int color[maxn];
int cnt1,cnt2;
int n,m;
struct Edge
{
int from,to;
};
vector<int>G[maxn];
vector<Edge>edges;
void add(int from,int to)
{
edges.push_back({from,to});
int m=edges.size();
G[from].push_back(m-1);
}
void init()
{
for(int i=0;i<=n;i++)
G[i].clear();
edges.clear();
memset(color,0,(n+1)*4);
}
int pow2(int k)
{
int res=1;
while(k--)
res=res*2%mod;
return res;
}
bool dfs(int u,int c)
{
color[u]=c;
if(c==1)
cnt1++;
else
cnt2++;
for(int i=0;i<G[u].size();i++)
{
Edge e=edges[G[u][i]];
int v=e.to;
if(!color[v]&&!dfs(v,3-c))
return false;
if(color[v]&&color[v]!=3-c)
return false;
}
return true;
}
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
scanf("%d %d",&n,&m);
init();
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d %d",&u,&v);
add(u,v);
add(v,u);
}
int ans=1;
for(int i=1;i<=n;i++)
{
if(!color[i])
{
cnt1=cnt2=0;
if(dfs(i,1))
{
ans=(ll)ans%mod*(pow2(cnt1)+pow2(cnt2))%mod;
}
else
{
ans=0;
break;
}
}
}
cout<<ans<<endl;
}
}