题目链接
题意
给定 n 个点 m 条边的无向无权图,点的编号为 1-n。
无自环和重边。
将图中的每个节点赋值,要求:
- 每个点的权值为1或2或3;
- 图中的每一条边都满足,其两端点权值之和必须为奇数。
问,一共多少方案数?
思路
因为每条边的两端点权值和都为奇数,所以一条边的一个节点肯定为 2,另一端点为 1 或者 3。
用 1,2 将整个图染色,1 的位置可以为 1 也可以为 3。相反,1,3 可以和 2 互换。
所以对于一个连通块的答案为
2
c
n
t
1
+
2
c
n
t
2
2^{cnt1} + 2^{cnt2}
2cnt1+2cnt2。
该图可能不连通,那么 x x x 个连通块的答案为所有连通块答案的乘积。
连通块中只有一个点的时候这个公式巧了,正好是3,其实应该特判一下的。
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
#define fi first
#define se second
#define endl '\n'
const int N = 300010, mod = 998244353;
int T, n, m;
int a[N];
vector<int> e[N];
int ans, col[N];
int t1, t2;
void bfs(int st)
{
queue<int> que;
que.push(st);
col[st] = 1;
t1 ++;
while(que.size())
{
int x = que.front();
que.pop();
for(auto tx : e[x])
{
if(col[tx] && col[tx] == col[x]) ans = -1;
if(col[tx]) continue;
if(col[x] == 1) col[tx] = 2, t2++;
else col[tx] = 1, t1++;
que.push(tx);
}
}
}
int qmi(int x, int y)
{
int ans = 1;
while(y)
{
if(y & 1) ans = (ans*x)%mod;
x = (x*x)%mod;
y >>= 1;
}
return ans;
}
signed main(){
Ios;
cin >> T;
while(T--)
{
cin >> n >> m;
for(int i=1;i<=n;i++) e[i].clear(), col[i] = 0;
while(m--)
{
int x,y;cin >> x >> y;
e[x].pb(y);
e[y].pb(x);
}
ans = 0;
int t = 0, sum = 1;
for(int i=1;i<=n;i++)
if(!col[i])
{
t1 = t2 = 0;
bfs(i);
// if(t2==0) sum = (sum*3)%mod;
// else
sum = sum*((qmi(2, t1) + qmi(2, t2))%mod)%mod;
}
if(ans == -1) cout << 0 << endl;
else cout << sum << endl;
}
return 0;
}
这个题赛上卡了好久,先是没想到存在图不连通的情况,然后又把方案计算方法搞错了,把整个图的 cnt1 和 cnt2 加一起最后再算。。前面几个样例竟然过了。。
还是不够熟练,挺简单的一道染色。。