1. 程式人生 > 實用技巧 >20200722T1 【NOIP2015模擬10.29A組】三色樹

20200722T1 【NOIP2015模擬10.29A組】三色樹

Description

給出一個N個節點的無根樹,每條邊有非負邊權,每個節點有三種顏色:黑,白,灰。
一個合法的無根樹滿足:樹中不含有黑色結點或者含有至多一個白色節點。
現在希望你通過割掉幾條樹邊,使得形成的若干樹合法,並最小化割去樹邊權值的和。

Input

第一行一個正整數N,表示樹的節點個數。
第二行N個整數Ai,表示i號節點的顏色,0表示黑色,1表示白色,2表示灰色。
接下來N-1行每行三個整數XiYiZi,表示一條連線Xi和Yi權為Zi的邊。

Output

輸出一個整數表示其最小代價。

Sample Input

5
01110
125
133
525
2416

Sample Output

10
樣例解釋:
花費10的代價刪去邊(1,2)和邊(2,5)。

Data Constraint

20%的資料滿足N≤10。
另外30%的資料滿足N≤100,000,且保證樹是一條鏈。
100%的資料滿足N≤300,000,0≤Zi≤1,000,000,000,Ai∈{0,1,2}。

solution

一眼顯然樹形DP

仔細思考發現不好轉移

還是暴力適合我

void add(int x,int y,int z)
{
    ver[++cut] = y; next[cut] = head[x]; head[x] = cut; w[cut] = z;
}
int lowbit(int x)
{
    return x&-x;
}
int count(int x) { int num = 0; for(; !(x&1); x >>= 1)num ++; return ++num ; } void dfs(int x,int fa) { book[x] = 1; if(color[x] == 1) white++; else if(color[x] == 0) black++; for(R int i = head[x]; i; i = next[i]) { int y = ver[i], z = w[i]; if
(y == fa)continue; dfs(y,x); } } bool check() { for(R int i = 1; i <= n; i++) { if(!book[i]) { black = 0; white = 0; dfs(i,0); if(black && white > 1)return false; } } return true; } signed main() { read(n); for(R int i = 1; i <= n; i++) read(color[i]); if(n<=10) { for(R int i = 1; i < n; i++) read(a[i]), read(b[i]), read(c[i]), SUM += c[i]; for(R int i = 0; i <= (1<<(n-1))-1; i++) { int now = i, sum = 0; cut = 0; memset(head,0,sizeof(head)); while(now) { int which = count(now ); add(a[which],b[which],c[which]); sum += c[which]; now -= lowbit(now); } memset(book,0,sizeof(book)); if(check()) ans = min(ans,SUM - sum ); } writeln(ans); return 0; } writeln(0); return 0; }

問鏈就是打掛了

正解貌似從下往上掃

dp[i][0 / 1 / 2] 在i節點,0表示沒有黑色,1表示沒有白色,2表示有一個白色

code

埋坑