1. 程式人生 > >[CQOI2009]葉子的染色

[CQOI2009]葉子的染色

當前 最小 sin 少包 ont max 個數 顏色 pan

題目描述

給一棵m個結點的無根樹,你可以選擇一個度數大於1的結點作為根,然後給一些結點(根、內部結點和葉子均可)著以黑色或白色。你的著色方案應該保證根結點到每個葉子的簡單路徑上都至少包含一個有色結點(哪怕是這個葉子本身)。 對於每個葉結點u,定義c[u]為從根結點從U的簡單路徑上最後一個有色結點的顏色。給出每個c[u]的值,設計著色方案,使得著色結點的個數盡量少。

輸入輸出格式

輸入格式:

第一行包含兩個正整數m, n,其中n是葉子的個數,m是結點總數。結點編號為1,2,...,m,其中編號1,2,... ,n是葉子。以下n行每行一個0或1的整數(0表示黑色,1表示白色),依次為c[1],c[2],...,c[n]。以下m-1行每行兩個整數a,b(1<=a < b <= m),表示結點a和b 有邊相連。

輸出格式:

僅一個數,即著色結點數的最小值。

輸入輸出樣例

輸入樣例#1:
5 3
0
1
0
1 4
2 5
4 5
3 5
輸出樣例#1:
2

說明

M<=10000

N<=5021

解析:

樹形dp

選擇一個不是葉子節點的點做跟來遍歷整棵樹

dp[i][j]用來表示當前我們在i這個節點,當前這個節點染成j色的時候,子樹染色需要的最小值

然後怎麽轉移呢,就是當他的子節點要有和他染成相同顏色的,就可以染到當前的點,他的子樹如果染別的顏色的

個數就統計在自己身上

代碼:

#include<cstdio>
#include
<algorithm> #include<iostream> #define MAXN 10010 using namespace std; struct Edge{ int vi; int vj; int next; }edge[1001011]; int head[MAXN]; int now = 0; int rudu[MAXN]; int c[MAXN]; int dp[MAXN][2]; void dfs(int now,int fa) { if(rudu[now] == 1) { dp[now][c[now]]
= 1; dp[now][c[now]^1] = 0x7ffffff; return; } dp[now][1] = dp[now][0] = 1; for(int i = head[now];i;i = edge[i].next) { int vj = edge[i].vj; if(vj == fa)continue; dfs(vj,now); dp[now][1] += min(dp[vj][1] - 1,dp[vj][0]); dp[now][0] += min(dp[vj][1],dp[vj][0] - 1); } } void push(int vi,int vj) { now++; edge[now].vi = vi; edge[now].vj = vj; edge[now].next = head[vi]; head[vi] = now; } int main() { int n,m; scanf("%d%d",&m,&n); for(int i = 1;i <= n;i++) { scanf("%d",&c[i]); } for(int i = 1;i < m;i++) { int vi,vj; scanf("%d%d",&vi,&vj); push(vi,vj); push(vj,vi); rudu[vi]++; rudu[vj]++; } rudu[m]++; dfs(m,0); printf("%d",min(dp[m][0],dp[m][1])); return 0; }

[CQOI2009]葉子的染色