【2010福建】收稻子 (校BSOJ1114)
農夫有n塊農田,農田里種滿了稻子。秋天到了,稻子熟了,每塊農田都有一定數量的稻子。我們可以把農田看成n個點,編號是1到n。農夫起點編號是1。恰好有n-1條道路連接這些點,每條道路長度都為1,并且任意2點都是可達的。每條道路都有一定的長度。現在農夫從起點出發(fā),到農田收割稻子。農夫每經過一塊農田就能收割該農田里的稻子。但是農夫是如此的懶惰,他可不想走過的總路程超過m。農夫應該如何選擇一種收割方案使得到的稻子最多。農夫最后可以停在任意點!
Input
? ? ? 第一行一個正整數n(1<=n<=100)表示農田數;
? ? ? 第二行n個整數(不大于1000)表示每塊農田的稻子數。
接著n-1行每行兩個整數a,b,表示a和b之間有一條長度為1的道路,道路是雙向的。
最后一行一個整數m(0<=m<=200)表示農夫最多走m的路程。
2
1 1
1 2
1
?
Output
? ? ?輸出一個整數,表示農夫能得到最多的稻子。
2
?
根據題目的數據范圍,n<=100,m<=200,想到樹形dp。
令1為根,設g[i][j]表示在i為根的子樹中,以i為起點,最多走j的路程,得到的最多麥子數。
ans=g[1][m]
但只設一個并不能寫出轉移方程,比如節(jié)點i,它可能走向一個兒子y1,然后返回到 i,再走向另一個兒子y2。
所以這里設一個輔助用的數組f
設f[i][j]表示在i為根的子樹中,以i為起點,最多走j的路程,又回到了 i,得到的最多麥子數。
令y為i的一個兒子
方程:? ? ? (走y后又回來)? g[i][j]=max(g[i][j],g[i][j-k-2]+f[y][k]);
? ? ? ? ? ? ? ? ?(走y后不回來)g[i][j]=max(g[i][j],f[i][j-k-1]+g[y][k]);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??f[i][j]=max(f[i][j],f[i][j-k-2]+f[y][k]);
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 int n,m,cnt; 9 int h[105]; 10 int v[105]; 11 int f[105][205],g[105][205]; 12 struct node{int to,next;}a[205]; 13 void add(int x,int y){cnt++;a[cnt].to=y;a[cnt].next=h[x];h[x]=cnt;} 14 void dp(int x,int fa) 15 { 16 int i,j,k,y; 17 for(i=0;i<=m;i++)f[x][i]=g[x][i]=v[x]; 18 for(i=h[x];i;i=a[i].next) 19 { 20 y=a[i].to; 21 if(y==fa)continue; 22 dp(y,x); 23 for(j=m;j>=0;j--) 24 for(k=0;k<=j-2;k++) 25 g[x][j]=max(g[x][j],g[x][j-k-2]+f[y][k]); 26 for(j=m;j>=0;j--) 27 for(k=0;k<=j-1;k++) 28 g[x][j]=max(g[x][j],f[x][j-k-1]+g[y][k]); 29 for(j=m;j>=0;j--) 30 for(k=0;k<=j-2;k++) 31 f[x][j]=max(f[x][j],f[x][j-k-2]+f[y][k]); 32 } 33 } 34 int main() 35 { 36 int n,x,y,i; 37 cin>>n; 38 for(i=1;i<=n;i++)scanf("%d",&v[i]); 39 for(i=1;i<=n-1;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x); 40 cin>>m; 41 dp(1,0); 42 cout<<g[1][m]; 43 return 0; 44 }?
??
?
轉載于:https://www.cnblogs.com/dsb-y/p/11427379.html
總結
以上是生活随笔為你收集整理的【2010福建】收稻子 (校BSOJ1114)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: inline函数
- 下一篇: Integer.highestOneBi