1. 程式人生 > >HDU 4616 Game(經典樹形dp+最大權值和鏈)

HDU 4616 Game(經典樹形dp+最大權值和鏈)

using bsp mes size hdu pen typedef style 最大的

http://acm.hdu.edu.cn/showproblem.php?pid=4616

題意:
給出一棵樹,每個頂點有權值,還有存在陷阱,現在從任意一個頂點出發,並且每個頂點只能經過一次,如果經過了c個陷阱就不能再走了,計算最大能獲得的權值和。

思路:
有點像樹鏈剖分,對於一個以u為根的子樹,因為每個頂點只能經過一次,那我們只能選擇它的一個子樹往下走。就像是把這棵樹分成許多鏈,最後再連接起來。

這道題目麻煩的地方是陷阱的處理,用d【u】【j】【0/1】表示以u為根的某一子節點經過j個陷阱後到達u的最大權值和,0/1表示起點是否有陷阱。

假設當前到達u時經過了k個陷阱,分下面幾種情況進行討論:

①如果k==c,那麽起點和終點至少有一個是陷阱(可能有些人會認為終點一定會是陷阱,這樣是沒錯的,因為起點和終點時相對的,你也可以把起點看做終點)。

②如果k<c,那麽起點和終點是否是陷阱是任意的,可以有也可以沒有。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<sstream>
 6 #include<vector>
 7 #include<stack>
 8
#include<queue> 9 #include<cmath> 10 #include<map> 11 #include<set> 12 using namespace std; 13 typedef long long ll; 14 typedef pair<int,int> pll; 15 const int INF = 0x3f3f3f3f; 16 const int maxn = 50000 + 5; 17 18 int n,c; 19 int ans; 20 int val[maxn], trap[maxn];
21 int d[maxn][5][2]; 22 vector<int> G[maxn]; 23 24 void dfs(int u, int fa) 25 { 26 d[u][trap[u]][trap[u]]=val[u]; 27 28 for(int i=0;i<G[u].size();i++) 29 { 30 int v=G[u][i]; 31 if(v==fa) continue; 32 dfs(v,u); 33 34 //計算以u為根的子樹所能獲得的最大值,也就是將子樹的鏈進行連接 35 for(int j=0;j<=c;j++) 36 { 37 for(int k=0;j+k<=c;k++) 38 { 39 if(j!=c) ans=max(ans,d[u][j][0]+d[v][k][1]); 40 if(k!=c) ans=max(ans,d[u][j][1]+d[v][k][0]); 41 if(j+k<c) ans=max(ans,d[u][j][0]+d[v][k][0]); //起點和終點都可以為非陷阱 42 if(k+j<=c) ans=max(ans,d[u][j][1]+d[v][k][1]); //起點和終點都可以為陷阱 43 } 44 } 45 46 47 for(int j=0;j+trap[u]<=c;j++) //更新以u的根的子樹中權值最大的鏈 48 { 49 d[u][j+trap[u]][0]=max(d[u][j+trap[u]][0],d[v][j][0]+val[u]); 50 //這兒要註意一下,如果j=0時,要麽就不能從有陷阱的起點出發 51 if(j!=0) d[u][j+trap[u]][1]=max(d[u][j+trap[u]][1],d[v][j][1]+val[u]); 52 } 53 } 54 } 55 56 int main() 57 { 58 //freopen("in.txt","r",stdin); 59 int T; 60 scanf("%d",&T); 61 while(T--) 62 { 63 scanf("%d%d",&n,&c); 64 for(int i=0;i<n;i++) G[i].clear(); 65 66 for(int i=0;i<n;i++) 67 scanf("%d%d",&val[i],&trap[i]); 68 69 for(int i=1;i<n;i++) 70 { 71 int u,v; 72 scanf("%d%d",&u,&v); 73 G[u].push_back(v); 74 G[v].push_back(u); 75 } 76 77 ans=0; 78 memset(d,0,sizeof(d)); 79 dfs(0,-1); 80 printf("%d\n",ans); 81 } 82 return 0; 83 }

HDU 4616 Game(經典樹形dp+最大權值和鏈)