爐石傳說:中速卡組的好朋友!新卡劍聖使用指南!
阿新 • • 發佈:2022-04-01
Description
給一棵m個結點的無根樹,你可以選擇一個度數大於1的結點作為根,然後給一些結點(根、內部結點和葉子均可)著以黑色或白色。你的著色方案應該保證根結點到每個葉子的簡單路徑上都至少包含一個有色結點(哪怕是這個葉子本身)。
對於每個葉結點u,定義 \(c[u]\) 為從 \(u\) 到根結點的簡單路徑上第一個有色結點的顏色。給出每個 \(c[u]\) 的值,設計著色方案,使得著色結點的個數儘量少。
Solution
先給出一個結論:對於任意一個可行根,對答案沒有影響。
- 證明:設當前根為 \(x\),有一與其相連的 \(y\) 。若 \(x\) 和 \(y\) 都有顏色,則可以得出 \(x\)
那麼根據這個結論,不妨隨便找一個根。
考慮樹形 \(dp\)。設 \(f_{i,0/1/2}\) 表示當前節點 \(i\) 塗 0,1 或者不塗。
先考慮有顏色的。轉移分為葉子結點和非葉節點。
對於 \(f_{i,0}\),如果 \(son\) 是葉子節點並且要 1 ,那麼 \(f_{i,0}+1\)。如果是非葉節點,\(f_{i,0}=\sum\min(\min(f_{son,0}-1,f_{son,1}),f_{son,2})\)。
對於 \(f_{i,1}\) 同理。
而對於 \(f_{i,2}\)
初值:對於葉子結點,\(f_{i,c_i}=1,f_{i,1-c_i}=f_{i,2}=\inf\),對於非葉節點 \(f_{i,0/1}=1\)。
Code
#include<cstdio> #include<algorithm> #define N 100005 #define inf 123456789 using namespace std; struct node { int to,next,head; }a[N<<1]; int n,m,rt,x,y,tot,c[N],f[N][3]; void add(int x,int y) {a[++tot].to=y;a[tot].next=a[x].head;a[x].head=tot;} void dfs(int x,int fa) { if (x>m) f[x][0]=f[x][1]=1; for (int i=a[x].head;i;i=a[i].next) { int y=a[i].to; if (y==fa) continue; dfs(y,x); if (y<=m) {if (c[y]==1) f[x][0]++;} else f[x][0]+=min(min(f[y][0]-1,f[y][1]),f[y][2]); if (y<=m) {if (c[y]==0) f[x][1]++;} else f[x][1]+=min(min(f[y][1]-1,f[y][0]),f[y][2]); f[x][2]+=min(min(f[y][0],f[y][1]),f[y][2]); } } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;++i) scanf("%d",&c[i]),f[i][c[i]]=1,f[i][c[i]^1]=f[i][2]=inf; rt=m+1; for (int i=1;i<n;++i) { scanf("%d%d",&x,&y); add(x,y);add(y,x); } dfs(rt,0); printf("%d\n",min(min(f[rt][0],f[rt][1]),f[rt][2])); return 0; }