link
给出一个图 ,给图染色,可以染红色,蓝色,绿色,要求相同颜色的不能相邻,问有几种方案
\(N<=20\)
solve
我们观察 \(N\) 非常小,所以考虑暴力。
显然 \(3^n\) 是不行的,但是考虑到只有起点是可以放三个颜色的,其他都只能放两个颜色,所以复杂度是 \(2^n\)
code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 30;
int tem[maxn], cnt, n, m;
int g[maxn][maxn], c[maxn];
bool st[maxn];
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
void dfs(int u) { //将所有连通块中的点存到tem数组
st[u] = 1;
tem[cnt ++] = u;
for (int i = 1; i <= n; i ++) {
if (!st[i] && g[i][u]) dfs(i);
}
}
bool check(int u, int j) { //判断点u是否可以染成颜色j
for (int i = 1; i <= n; i ++) {
if (g[u][i] && c[i] == j) return false;
}
return true;
}
void dfs(int u, int &res) {
if (u == cnt) {
res ++; //枚举完所有点,方案数加1
return ;
}
for (int i = 1; i <= 3; i ++) {
if (check(tem[u], i)) {
c[tem[u]] = i;
dfs(u + 1, res);
c[tem[u]] = 0; //tem[u]点的颜色归为0,避免对tem[0] ~ tem[u - 1]点染色产生干扰
}
}
}
int main(){
n=read();m=read();
while (m --) {
int a, b;
a=read();b=read();
g[a][b] = g[b][a] = 1;
}
LL ans = 1;
for (int i = 1; i <= n; i ++) {
if (!st[i]) {
cnt = 0; //重置tem数组元素的个数
dfs(i); //获得连所有通块中的点
int t = 0; //记录连通块染色的方案数
dfs(0, t); //计算染色方案数
ans = ans * t; //不同连通块之间的方案数独立,答案是各连通块染色方案的乘积
}
}
printf("%lld\n",ans);
return 0;
}