1. 程式人生 > 實用技巧 >1010. 【CQOI2009】葉子的顏色

1010. 【CQOI2009】葉子的顏色

洛谷AC通道!

題目讓我們求最小染色數量,很容易想到dp。

設 $f_{i, 1/0}$ 表示第i個點染黑、白的最小數量, 初始值均為1(自己一條路)。如果這個點為葉子節點,即已經規定了第一個染色點,那麼相反顏色的f因設為inf(不能選擇它)。

那麼,如何選根? 看下圖(轉載的hhh),無論我們選擇1節點還是2節點,可以發現,只要不是葉子節點,根的變化對答案沒有影響。

那麼,我們就可以很愉快地得到狀態轉移方程了:

$f_{u, 0} += min(f_{v,1}, f_{v, 0} - 1)$

$f_{u,1} += min (f_{v,0}, f_{v,1} - 1)$

程式碼:

#include <bits/stdc++.h>
using
namespace std; #define N 100010 const int inf = (int)1e10; inline int read(){ int x = 0, s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); } return
x * s; } struct node{ int v, next; } t[N << 1]; int f[N]; int dp[N][2]; int bian = 0; inline void add(int u, int v){ t[++bian] = (node){v, f[u]}, f[u] = bian; t[++bian] = (node){u, f[v]}, f[v] = bian; return ; } int c[N]; int n, m; void dfs(int now, int fa){ dp[now][0] = dp[now][1
] = 1; if(now <= m){ if(c[now] == 0) dp[now][1] = inf; else dp[now][0] = inf; } for(int i = f[now]; i; i = t[i].next){ int v = t[i].v; if(v != fa){ dfs(v, now); dp[now][0] += min(dp[v][1], dp[v][0] - 1); dp[now][1] += min(dp[v][0], dp[v][1] - 1); } } return ; } int main(){ n = read(), m = read();// n 節點總數 m: 葉子 for(int i = 1;i <= m; i++) c[i] = read(); for(int i = 1;i < n; i++){ int x = read(), y = read(); add(x , y); } dfs(m + 1, m + 1); int ans = min(dp[m+1][0], dp[m+1][1]); cout << ans << endl; return 0; }