1. 程式人生 > >HihoCoder 1055 : 刷油漆 樹形DP第一題

HihoCoder 1055 : 刷油漆 樹形DP第一題

tdi 進行 vector coder div 評分 好玩的 scan style

刷油漆

時間限制:10000ms 單點時限:1000ms 內存限制:256MB

描述

上回說到,小Ho有著一棵灰常好玩的樹玩具!這棵樹玩具是由N個小球和N-1根木棍拼湊而成,這N個小球都被小Ho標上了不同的數字,並且這些數字都是處於1..N的範圍之內,每根木棍都連接著兩個不同的小球,並且保證任意兩個小球間都不存在兩條不同的路徑可以互相到達。沒錯,這次說的還是這棵樹玩具的故事!

小Ho的樹玩具的質量似乎不是很好,短短玩了幾個星期,便掉漆了!

“簡直是一場噩夢!”小Ho拿著樹玩具眼含熱淚道。

“這有什麽好憂傷的,自己買點油漆刷一刷不就行了?”小Hi表示不能理解。

“還可以這樣?”小Ho頓時興高采烈了起來,立馬跑出去買回來了油漆,但是小Ho身上的錢卻不夠——於是他只買回了有限的油漆,這些油漆最多能給M個結點塗上顏色,這就意味著小Ho不能夠將他心愛的樹玩具中的每一個結點都塗上油漆!

小Ho低頭思索了半天——他既不想只選一部分結點補漆,也不想找小Hi借錢,但是很快,他想出了一個非常棒的主意:將包含1號結點的一部分連通的結點進行塗漆(這裏的連通指的是這一些塗漆的結點可以互相到達並且不會經過沒有塗漆的結點),然後將剩下的結點拆掉!

那麽究竟選擇哪些結點進行塗漆呢?小Ho想了想給每個結點都評上了分——他希望最後留下來,也就是塗漆了的那些結點的評分之和可以盡可能的高!

那麽,小Ho該如何做呢?

輸入

每個測試點(輸入文件)有且僅有一組測試數據。

每組測試數據的第一行為兩個整數N、M,意義如前文所述。

每組測試數據的第二行為N個整數,其中第i個整數Vi表示標號為i的結點的評分

每組測試數據的第3~N+1行,每行分別描述一根木棍,其中第i+1行為兩個整數Ai,Bi,表示第i根木棍連接的兩個小球的編號。

對於100%的數據,滿足N<=10^2,1<=Ai<=N, 1<=Bi<=N, 1<=Vi<=10^3, 1<=M<=N

小Hi的Tip:那些用數組存儲樹邊的記得要開兩倍大小哦!

輸出

對於每組測試數據,輸出一個整數Ans,表示使得塗漆結點的評分之和最高可能是多少。

樣例輸入
10 4
370 328 750 930 604 732 159 167 945 210 
1 2
2 3
1 4
1 5
4 6
4 7
4 8
6 9
5 10
樣例輸出
2977

數據小的話用vector也方便得很

#include<cstdio>
#include
<cstdlib> #include<iostream> #include<algorithm> #include<cstring> #include<memory> using namespace std; const int maxn=110; const int maxm=220; int vis[maxn],n,m; int dp[maxn][maxn],V[maxn]; int Laxt[maxm],Next[maxm],To[maxm],cnt; void _add(int u,int v) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; } int _dfs(int u) { vis[u]=true; for(int i=Laxt[u];i;i=Next[i]){ int v=To[i]; if(vis[v]) continue; _dfs(v); for(int j=m;j>=2;j--){ for(int k=0;k<j;k++) dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]); } } } int main() { int i,j,u,v; while(~scanf("%d%d",&n,&m)){ cnt=0; memset(Laxt,0,sizeof(Laxt)); for(i=1;i<=n;i++) { scanf("%d",&V[i]); dp[i][1]=V[i]; } for(i=1;i<n;i++){ scanf("%d%d",&u,&v); _add(u,v); _add(v,u); } _dfs(1); printf("%d\n",dp[1][m]); } return 0; }

HihoCoder 1055 : 刷油漆 樹形DP第一題