標籤:
Apple Tree
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 7893 Accepted: 2642
Description
Wshxzt is a lovely girl. She likes apple very much. One day HX takes her to an apple tree. There are N nodes in the tree. Each node has an amount of apples. Wshxzt starts her happy trip at one node. She can eat up all the apples in the nodes she reaches. HX is a kind guy. He knows that eating too many can make the lovely girl become fat. So he doesn’t allow Wshxzt to go more than K steps in the tree. It costs one step when she goes from one node to another adjacent node. Wshxzt likes apple very much. So she wants to eat as many as she can. Can you tell how many apples she can eat in at most K steps.
Input
There are several test cases in the input
Each test case contains three parts.
The first part is two numbers N K, whose meanings we have talked about just now. We denote the nodes by 1 2 … N. Since it is a tree, each node can reach any other in only one route. (1<=N<=100, 0<=K<=200)
The second part contains N integers (All integers are nonnegative and not bigger than 1000). The ith number is the amount of apples in Node i.
The third part contains N-1 line. There are two numbers A,B in each line, meaning that Node A and Node B are adjacent.
Input will be ended by the end of file.
Note: Wshxzt starts at Node 1.
Output
For each test case, output the maximal numbers of apples Wshxzt can eat at a line.
Sample Input
2 1
0 11
1 2
3 2
0 1 2
1 2
1 3
Sample Output
11
2
題解:這道題我開始想的是用f[i][j]表示在i節點的時候已經走了j步時的取到的最多的蘋果數。但是我發現這樣做對於兩個在不同子樹中節點的LCA到根節點的這一段距離會重複計算。
所以我們把需要動規方程所表示的狀態換一下:f[i][j]表示到節點i的時候在i的子樹中已經走了j步時的取到的最多的蘋果。
我們再考慮怎樣用子樹去更新:因為這樣的情況比較多,所以我們可以考慮用背包來解決這個問題。
但是我們需要注意一個問題:那就是題目中說可能會走到一個節點以後就不再往回走了,對於這種問題,我們還需要在改進一下動規方程:f[i][j][0]表示到節點i的時候在i的子樹中已經走了j步而且不能再回到這個節點取到的最多的蘋果;f[i][j][1]就表示可以回來的。
那麼動規方程就是:
f[i][j][1]=max(f[i][j][1],f[i][j-t][1]+f[son][t-2][1])(表示走到子節點再走回來,在走向子節點喝回來的過程中需要走兩條邊,所以減去)
f[i][j][0]=max(f[i][j][0],f[i][j-t][1]+f[son][t-1][1])(表示從另外的位元組點走到根節點之後,走到son節點,不回來,由於只是下去沒有再回來,所以只是-1)
f[i][j][0]=max(f[i][j][0],f[i][j-t][1]+f[son][t-2][1])(表示從送節點回到根節點後,再從根節點向下走不回來的時候的最大值,因為這個時候跟第一種一樣來回總共走了兩次,所以-2)
這樣以後這個問題我們就可以解決了。
#include<iostream>#include<cstdio>#include<cstring>#include<vector>using namespace std;const int N=110;const int K=210;vector <int> tr[N];int t,n,k,a[N],f[N][K][2];void dp(int x,int last){ int i,j,u,l; for(i=0;i<tr[x].size();++i){ u=tr[x][i]; if(u==last) continue; dp(tr[x][i],x); for(j=k;j>=1;--j){ for(l=1;l<=j;++l){ f[x][j][1]=max(f[x][j][1],f[x][j-l][1]+f[u][l-2][1]); f[x][j][0]=max(f[x][j][0],f[x][j-l][1]+f[u][l-1][0]); f[x][j][0]=max(f[x][j][0],f[x][j-l][0]+f[u][l-2][1]); } } }}int main(){ while(scanf("%d%d",&n,&k)==2){ int i,j,x,y; for(i=1;i<N;++i) tr[i].clear(); memset(f,0,sizeof(f)); for(i=1;i<=n;++i){ scanf("%d",&a[i]); for(j=0;j<=k;++j){ f[i][j][0]=f[i][j][1]=a[i]; } } for(i=1;i<n;++i){ scanf("%d%d",&x,&y); tr[x].push_back(y); tr[y].push_back(x); } dp(1,0); printf("%d\n",max(f[1][k][0],f[1][k][1])); }}
【poj2486】【Apple Tree】【樹形dp】