題目鏈接: /
題目
給定一顆個節點組成的樹,種顏色,其中個節點已染色,要求任意兩相鄰節點顏色不同,求合法染色方案數。
輸入
第行:和
第行:和代表點和點
第行:和代表點已經被塗上了顏色
輸出
合法的染色方案數
樣例輸入
4 1
1 2
1 3
1 4
4 3
樣例輸出
8
數據範圍
,
,
,
思路
這道題是一道樹形。
我們設爲在點塗顏色的方案數,那麼首先初始化,我們把所有點塗所有顏色的方案數都是。
接着,我們來處理數據中直接塗了顏色的點。這個也很好做,就是把這個點塗了的顏色的方案數標爲,剩下的兩個顏色方案數標爲。
接着我們就要開始,就按照與一個點相鄰的點不能跟它是同一個顏色的原則,我們就可以寫出式。
注意:
- 要開
- 要記得取模
代碼
#include<cstdio>
#include<cstring>
#define mo 1000000007
#define ll long long
using namespace std;
struct node{
int to, next;
}e[200001];
int n, k, x, y, kk, le[200001];
ll f[200001][4];
void add(int x, int y) {//連邊
e[++kk] = (node){y, le[x]}; le[x] = kk;
}
void dfs(int now, int fa) {//樹形dp
for (int i = le[now]; i; i = e[i].next)
if (e[i].to != fa) {
dfs(e[i].to, now);
f[now][1] = f[now][1] * ((f[e[i].to][2] + f[e[i].to][3]) % mo) % mo;//三個dp式,分別表示塗這三個顏色的方案數
f[now][2] = f[now][2] * ((f[e[i].to][1] + f[e[i].to][3]) % mo) % mo;
f[now][3] = f[now][3] * ((f[e[i].to][1] + f[e[i].to][2]) % mo) % mo;
}
}
int read() {//快讀
int re = 0, zf = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c = '-') zf = -zf;
c = getchar();
}
while (c >= '0' && c <= '9') {
re = re * 10 + c - 48;
c = getchar();
}
return re * zf;
}
int main() {
// freopen("barnpainting.in", "r", stdin);
// freopen("barnpainting.out", "w", stdout);
n = read();//讀入
k = read();//讀入
for (int i = 1; i <= n; i++)
f[i][1] = f[i][2] = f[i][3] = 1;//初始化
for (int i = 1; i < n; i++) {
x = read();//讀入
y = read();//讀入
add(x, y);//連邊
add(y, x);//兩個方向又要連邊
}
for (int i = 1; i <= k; i++) {
x = read();//讀入
y = read();//讀入
for (int i = 1; i <= 3; i++)
f[x][i] = 0;//如果一個點已經塗色,那麼這個點就不可能塗其他顏色
f[x][y] = 1;//就只能塗這個顏色
}
dfs(1, 0);//樹形dp
printf("%lld", (f[1][1] + f[1][2] + f[1][3]) % mo);//輸出答案
// fclose(stdin);
// fclose(stdout);
return 0;
}