1. 问题描述:
给定一个 n 个点 m 条边的无向无权图。点的编号为 1∼n,图中不含重边和自环。现在,请你给图中的每个点进行赋值,要求:每个点的权值只能是 1 或 2 或 3。对于图中的每一条边,其两端点的权值之和都必须是奇数,请问,共有多少种不同的赋值方法。由于结果可能很大,你只需要输出对 998244353 取模后的结果。
输入格式
第一行包含整数 T,表示共有 T 组测试数据,数据第一行包含两个整数 n,m,接下来 m 行,每行包含两个整数 u,v,表示点 u 和点 v 之间存在一条边。
输出格式
一个整数,表示不同赋值方法的数量对 998244353 取模后的结果
数据范围
输入样例:
2
2 1
1 2
4 6
1 2
1 3
1 4
2 3
2 4
3 4
输出样例:
4
0
来源:https://www.acwing.com/problem/content/description/4418/
2. 思路分析:
分析题目可以知道 n 个点 m 条边的无向图可能是不连通的,而且可以发现不同连通块之间是相互独立的,所以我们可以分别计算每一个连通块的方案数目,最终每一个连通块的方案数目相乘就是答案,由于任意两个端点的权值之和为奇数,所以肯定其中一个点的权值为奇数,另外一个点的权值为偶数,根据这个特点可以发现满足这个条件的无向图是二分图(可以将图中的点分为两大类且这些点分别属于两个不同的集合),而二分图中存在三个相互推导的充要条件,其中有一个充要条件是如果一个图是二分图那么染色法不存在矛盾,如果存在矛盾那么就不是二分图,方案数目就是 0,所以我们只需要计算二分图的方案数目即可,我们可以在遍历无向图节点的过程中对其染色,并且统计一下每个集合中点的数目 s1,s2,如果当前的图是二分图那么方案数目为 2 ^ s1 + 2 ^ s2(由于每个点奇数权值有两种所以方案数目为 2 ^ s1 或者 2 ^ s2),分别计算每一个连通块的方案数目乘起来就是答案:
3. 代码如下:
python(dfs):超时:
import sys
from typing import List
class Solution:
# s1, s2分别记录两个集合中点的数目
s1 = s2 = None
# 计算2的n次幂
def power2(self, n: int, mod: int):
res = 1
for i in range(n):
res = res * 2 % mod
return res
# u 表示当前节点, col 表示当前节点需要染成的颜色
def dfs(self, u: int, c: int, color: List[int], g: List[List[int]]):
color[u] = c
if c == 1:
self.s1 += 1
else:
self.s2 += 1
for next in g[u]:
# 下一个节点未染色那么将其染成 3 - c 的颜色, 发现矛盾返回False
if color[next] == 0 and not self.dfs(next, 3 - c, color, g):
return False
# 已经染色判断是否存在矛盾
elif color[next] != 0 and color[next] != 3 - c:
return False
return True
def process(self):
T = int(input())
mod = 998244353
while T > 0:
res = 1
n, m = map(int, input().split())
g = [list() for i in range(n + 10)]
for i in range(m):
# 添加无向边
a, b = map(int, input().split())
g[a].append(b)
g[b].append(a)
color = [0] * (n + 10)
for i in range(1, n + 1):
if color[i] == 0:
self.s1 = self.s2 = 0
if not self.dfs(i, 1, color, g):
res = 0
break
# 计算当前集合的方案数目
res = res * (self.power2(self.s1, mod) + self.power2(self.s2, mod)) % mod
print(res)
T -= 1
if __name__ == '__main__':
sys.setrecursionlimit(10 ** 5)
Solution().process()
python(bfs):超时:
import collections
from typing import List
class Solution:
s1 = s2 = None
def power2(self, n: int, mod: int):
res = 1
for i in range(n):
res = res * 2 % mod
return res
# bfs 染色
def bfs(self, u: int, c: int, color: List[int], g: List[List[int]]):
q = collections.deque([(u, c)])
color[u] = c
while q:
p = q.popleft()
c = p[1]
if c == 1:
self.s1 += 1
else:
self.s2 += 1
for next in g[p[0]]:
if color[next] != 0 and color[next] != 3 - c: return False
elif color[next] == 0:
color[next] = 3 - c
q.append((next, 3 - c))
return True
def process(self):
T = int(input())
mod = 998244353
while T > 0:
res = 1
n, m = map(int, input().split())
g = [list() for i in range(n + 10)]
for i in range(m):
a, b = map(int, input().split())
g[a].append(b)
g[b].append(a)
color = [0] * (n + 10)
for i in range(1, n + 1):
if color[i] == 0:
self.s1 = self.s2 = 0
if not self.bfs(i, 1, color, g):
res = 0
break
res = res * (self.power2(self.s1, mod) + self.power2(self.s2, mod)) % mod
print(res)
T -= 1
if __name__ == '__main__':
Solution().process()
go:数组模拟邻接表:
package main
import (
"bufio"
"fmt"
"io"
"os"
)
const N, M, mod = 300010, N * 2, 998244353
var (
idx, s1, s2 int
h, color [N]int
e, ne [M]int
)
func add(a, b int) {
e[idx] = b
ne[idx] = h[a]
h[a] = idx
idx += 1
}
func dfs(u int, c int) bool {
color[u] = c
if c == 1 {
s1 += 1
} else {
s2 += 1
}
for i := h[u]; i != -1; i = ne[i] {
j := e[i]
if color[j] == 0 && !dfs(j, 3-c) {
return false
} else if color[j] != 0 && color[j] != 3-c {
return false
}
}
return true
}
func power2(n int) int {
res := 1
for i := 0; i < n; i++ {
res = res * 2 % mod
}
return res
}
func run(r io.Reader, w io.Writer) {
in := bufio.NewReader(r)
out := bufio.NewWriter(w)
defer out.Flush()
var T, n, m, a, b int
for fmt.Fscan(in, &T); T > 0; T -= 1 {
idx = 0
fmt.Fscan(in, &n, &m)
// 注意每次初始化的时候不要初始化整个数组, 否则也会 TLE
for i := 0; i < n + 10; i++ {
h[i] = -1
color[i] = 0
}
for i := 0; i < m; i++ {
fmt.Fscan(in, &a, &b)
add(a, b)
add(b, a)
}
res := 1
for i := 1; i <= n; i++ {
if color[i] == 0 {
s1 = 0
s2 = 0
if !dfs(i, 1) {
res = 0
break
}
res = res * (power2(s1) + power2(s2)) % mod
}
}
fmt.Fprintln(out, res)
}
}
func main() {
run(os.Stdin, os.Stdout)
}