題目描述
原題來自:CQOI 2009
給一棵有 m 個節點的無根樹,你可以選擇一個度數大於 11 的節點作爲根,然後給一些節點(根、內部節點、葉子均可)着以黑色或白色。你的着色方案應保證根節點到各葉子節點的簡單路徑上都包含一個有色節點,哪怕是葉子本身。
對於每個葉子節點 u,定義cu 爲從根節點到 u 的簡單路徑上最後一個有色節點的顏色。給出每個cu 的值,設計着色方案使得着色節點的個數儘量少。
輸入
第一行包括兩個數 m,n 依次表示節點總數和葉子個數,節點編號依次爲 1 至 m。
接下來 n 行每行一個 0 或 1 的數,其中 0 表示黑色,1 表示白色,依次爲 c1,c2,⋯,cn 的值。
接下來 m-1行每行兩個整數 a,b,表示節點 a 與 b 有邊相連。
輸出
輸出僅一個數,表示着色節點數的最小值。
樣例輸入
5 3
0
1
0
1 4
2 5
4 5
3 5
樣例輸出
2
提示
數據 | 11 | 22 | 33 | 44 | 55 | 66 | 77 | 88 | 99 | 1010 |
---|---|---|---|---|---|---|---|---|---|---|
m | 10 | 50 | 100 | 200 | 400 | 1000 | 4000 | 8000 | 10000 | 10000 |
n | 5 | 23 | 50 | 98 | 197 | 498 | 2044 | 4004 | 5021 |
4996 |
題解:
樹形dp
dp[x][0,1]表示在x的子樹中x選擇顏色0,1時的最小代價。
轉移方程:
dp[x][0]+=min(dp[to[i]][0]-1,dp[to[i]][1]);
dp[x][1]+=min(dp[to[i]][1]-1,dp[to[i]][0]);
代碼:
#include<bits/stdc++.h>
const int MAXN=100005;
const int INF=0x7f;
using namespace std;
int head[MAXN],to[MAXN],nxt[MAXN];
int dp[MAXN][5];
int tot=0;
int vis[MAXN];
int m,n;
void add(int x,int y)
{
tot++;
to[tot]=y;
nxt[tot]=head[x];
head[x]=tot;
return;
}
void dfs(int dep,int lat)
{
dp[dep][1]=1;
dp[dep][0]=1;
if(vis[dep]!=-1)dp[dep][!vis[dep]]=INF;
for(int e=head[dep];e;e=nxt[e])
{
int h=to[e];
if(h!=lat)
{
dfs(h,dep);
dp[dep][1]+=min(dp[h][0],dp[h][1]-1);
dp[dep][0]+=min(dp[h][1],dp[h][0]-1);
}
}
return;
}
int main()
{
for(int i=1;i<=100005;i++)vis[i]=-1;
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)scanf("%d",&vis[i]);
for(int i=1;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(n+1,0);
printf("%d\n",min(dp[n+1][0],dp[n+1][1]));
return 0;
}