三色樹 需要深度思考的樹形dp

2022-08-18 23:03:17 字數 2655 閱讀 5688

給出乙個n個節點的無根樹,每條邊有非負邊權,每個節點有三種顏色:黑,白,灰。

乙個合法的無根樹滿足:樹中不含有黑色結點或者含有至多乙個白色節點。

現在希望你通過割掉幾條樹邊,使得形成的若干樹合法,並最小化割去樹邊權值的和。

第一行乙個正整數n,表示樹的節點個數。

第二行n個整數ai,表示i號節點的顏色,0 表示黑色,1表示白色,2表示灰色。

接下來n-1行每行三個整數xi yi zi,表示一條連線xi和yi權為zi的邊。

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

5 0 1 1 1 0

1 2 5

1 3 3

5 2 5

2 4 16

10樣例解釋:

花費10的代價刪去邊(1, 2)和邊(2, 5)。

20%的資料滿足n≤10。

另外30%的資料滿足n≤100,000,且保證樹是一條鏈。

100%的資料滿足n≤300,000,0≤zi≤1,000,000,000,ai∈。

其實明眼人都能看出這是樹形dp,可是當我們仔細去思考該維護什麼時,我們就陷進去了。因為我們所想的任何方法的維護都十分的複雜,很容易給人一種思路錯了的錯覺。可是這題確確實實就是這麼複雜,很多人想得到方向,卻無法深入,接下來分析一下。

我們要維護的是3類情況(用f來表示):

1.f[i][0]表示以i為根節點的子樹在切割後不含黑點的最小代價;

2.f[i][1]表示以i為根節點的子樹在切割後不含白點的最小代價;

3.f[i][2]表示以i為根節點的子樹在切割後含乙個白點的最小代價;

按這樣分之後答案就是根節點s三個值的最小值

接下來考慮轉移方程:

1.當col[i](即該點顏色)=0時,明顯不符合無黑點,所以f[i][0]=inf(無窮大);而當col[i]!=0時,這時要考慮斷邊情況,很容易可以列得

$f[i][0]= \sum_$min(f[son][0],min(f[son][1],f[son][2])+w)<--w為邊權

2.當col[i]=1時,同樣的不符合無白點,所以f[i][1]=inf;而當col[i]!=1時,這時要考慮斷邊情況,一樣可以列得

$f[i][1]= \sum_$min(f[son][1],min(f[son][0],f[son][2])+w) (2與1幾乎一模一樣)

3.當col[i]=1時,這時該點已經是乙個白點了,所以方程式和2情況的第二種一樣。剩下最後一種情況(最複雜的一種),即col[i]!=1時,這時我們直接處理的話會列出一長串,但我們可以和f[i][1]結合起來,我們只要從最後算出的f[i][1]中減去一種min(f[son][1],min(f[son][0],f[son][2])+w)再加上f[son][2]就能維護乙個白點的情況,同樣的,我們要使f[i][2]最小化,而最終的

f[i][1]又是個定值,所以我們要最大化min(f[son][1],min(f[son][0],f[son][2])+w)+f[son][2].

所以最終方程式為:$f[i][2]= f[i][1](最終的)-max(min(f[son][1],min(f[son][0],f[son][2])+w)-f[son][2]).<--減號是因為加了個括號

1 #include2 #include3 #include4 #include5 #include6

using

namespace

std;

7#define debug printf("zjyvegetable\n")

8#define int long long

9 inline int

read()

12while(isdigit(c))

13return a*b;14}

15const

int n=4e5+50,m=2e6+50,inf=123456789012345678;16

int n,col[n],tot,vis[n],h[n],ver[m],nx[m],ed[m],f[n][3

],t[m],top;

17void add(int u,int v,int

z)21 inline void dfs(int

x)34

else

if(col[x]==1)38

else43}

44if(col[x]!=1)f[x][2]=f[x][1]-maxn;45}

46signed main()

54for(int i=1;i)

59 dfs(1

);60 printf("

%lld\n

",min(f[1][0],min(f[1][1],f[1][2

])));

61return0;

62 }

由於這題資料有長鏈,所以要用人工棧,而筆者由於懶而只打了dfs,拿不到全部分,望理解。

後來筆者在某題被迫學了人工棧,所以回來填坑了,這裡補一下人工棧部分**:

void fake_dfs(int

begin)

vis[x]=1

; }

else

else

if(col[x]==1

)

else

}if(col[x]!=1)f[x][2]=f[x][1]-maxn;}}

}

動態規劃 三色二叉樹

三色二叉樹 time limit 1s memory limit 32m accepted submit 81 total submit 211 一棵二叉樹可以按照如下規則表示成乙個由0 1 2組成的字串行,我們稱之為 二叉樹序列s 例如,下圖所表示的二叉樹可以用二叉樹序列s 21200110來表示...

BZOJ 1864 三色二叉樹 樹DP

僅有一行,不超過500000個字元,表示乙個二叉樹序列。輸出檔案也只有一行,包含兩個數,依次表示最多和最少有多少個點能夠被染成綠色。1122002010 5 2dp i 0 i節點不為綠色獲得的最大收益 dp i 1 i節點為綠色獲得的最大收益 include include include inc...

ZJOI 2006 三色二叉樹

顯然是樹形dp,可以在狀態轉移的過程中順便把樹給建出來,定義 f i j f i j 為當節點 i i 被染成顏色 j role presentation style position relative j j時,以 i i 為根的子樹中最多有多少個節點被染成綠色,g i j role presen...