HDOJ5543 Pick The Sticks

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5543

题目大意:有n个金条,每个金条有长度和价值,给一个长度为L的容器,当金条在容器两端的时候,只要重心在容器内也可以放下,问最多能获得的价值。

思路:01背包,但是重心怎么处理,最好的肯定是边界情况也就是刚好金条刚好能伸出一半,或者直接只取一根金条然后放在容器里面。

多开一位 dp[i][j][k]代表当前选第i个背包容量为j有k个超出边缘的金条时所能获得的最大价值

状态转移方程 dp[i][j][2]=max(dp[i-1][j-w[i]][2]+v[i],dp[i-1][j-w[i]/2][1]+v[i],dp[i][j][2])

      dp[i][j][1]=max(dp[i-1][j-w[i]][1]+v[i],dp[i-1][j-w[i]/2][0]+v[i],dp[i][j][1])

      dp[i][j][0]=max(dp[i-1][j-w[i]][0]+v[i],dp[i][j][0])

如果没有第一维i的话,那么j和k都要从大到小搞,很明显dp[j][1]是会影响到dp[j][2]的

处理整除的情况很简单,容器和金条长度都*2就好了,这样就能保证一定整除

最后不要忘了放一个的情况要特判一下

 1 #include <stdio.h>
 2 #include <iostream>
 3 #include <string.h>
 4 #include <algorithm>
 5 using namespace std;
 6 const int maxn=4010;
 7 long long dp[maxn][3];
 8 long long  v[maxn],w[maxn];
 9 void init(){
10     memset(dp,0,sizeof(dp));
11 }
12 void beibao(int pos,int V) {
13     for(int i=V;i>=w[pos]/2;i--) {
14         dp[i][2]=max(dp[i-w[pos]/2][1]+v[pos],dp[i][2]);
15         if(i>=w[pos])
16         dp[i][2]=max(dp[i-w[pos]][2]+v[pos],dp[i][2]);
17     }
18 
19     for(int i=V;i>=w[pos]/2;i--){
20         dp[i][1]=max(dp[i-w[pos]/2][0]+v[pos],dp[i][1]);
21         if(i>=w[pos])
22         dp[i][1]=max(dp[i-w[pos]][1]+v[pos],dp[i][1]);
23     }
24     for(int i=V;i>=w[pos];i--) 
25         dp[i][0]=max(dp[i-w[pos]][0]+v[pos],dp[i][0]);    
26 }
27 void solve(int T) {
28     init();
29     
30     int n,l;
31     scanf("%d %d",&n,&l);
32     l<<=1;
33     long long ans=0;
34     for(int i=1;i<=n;i++) {
35         scanf("%lld %lld",&w[i],&v[i]);
36         w[i]<<=1;
37         ans=max(ans,v[i]);
38     }
39     for(int i=1;i<=n;i++) {
40         beibao(i,l);
41     }
42     ans=max(ans,max(dp[l][0],max(dp[l][1],dp[l][2])));
43     printf("Case #%d: %lld\n",T,ans);
44 }
45 int main() {
46     int T;
47     scanf("%d",&T);
48     for(int i=1;i<=T;i++) solve(i);
49 }

 

posted @ 2016-11-17 22:27  as3asddd  阅读(203)  评论(0编辑  收藏  举报