您的位置:首页 > 其它

2015年CCPC D题 Pick The Sticks(DP)

2015-11-01 20:02 381 查看
0,10,1背包问题,赛后听了秦总队友的讲解会了。增加一维:

dp[k][i][v]dp[k][i][v]:

第一维:k=0,1,2k=0,1,2。00代表没有半截的情况,11代表有11个半截的情况,22代表有22个半截的情况。

第二维:前ii物品。

第三位:占了vv容量。

那么DPDP转移方程为:

dp[0][i][v]=max(dp[0][i−1][v],dp[0][i−1][v−c[i]]+w[i])dp[1][i][v]=max(dp[1][i−1][v],dp[1][i−1][v−c[i]]+w[i],dp[0][i−1][v−c[i]2]+w[i])dp[2][i][v]=max(dp[2][i−1][v],dp[2][i−1][v−c[i]]+w[i],dp[1][i−1][v−c[i]2]+w[i])dp[0][i][v]=max(dp[0][i-1][v],dp[0][i-1][v-c[i]]+w[i])\\
dp[1][i][v]=max(dp[1][i-1][v],dp[1][i-1][v-c[i]]+w[i],dp[0][i-1][v-{c[i]\over{2}}]+w[i])\\
dp[2][i][v]=max(dp[2][i-1][v],dp[2][i-1][v-c[i]]+w[i],dp[1][i-1][v-{c[i]\over{2}}]+w[i])

小tricktrick:

11:对于容量c[i]2{c[i]\over{2}}不能被22整除时,要把它变成整数,所以初始化的时候c[i]<<=1c[i]<<=1。

22:只放11个物品的时候,无论背包容量有多大,任何物品都能放进去。

代码:

#include <bits/stdc++.h>
#define LL long long
#define FOR(i,x,y)  for(int i = x;i < y;++ i)
#define IFOR(i,x,y) for(int i = x;i > y;-- i)

using namespace std;

const int Mod = 1000000007;

const int maxN = 1010;
const int maxL = 4040;

LL dp[3][maxL];

int n,l,c[maxN],w[maxN];

void init(){
scanf("%d%d",&n,&l);
l <<= 1;
FOR(i,1,n+1){
scanf("%d%d",&c[i],&w[i]);
c[i] <<= 1;
}
memset(dp,0,sizeof(dp));
}

LL DP0(int i,int v){
LL res = dp[0][v];
if(v >= c[i])   res = max(res,dp[0][v-c[i]]+w[i]);
return res;
}

LL DP1(int i,int v){
LL res = dp[1][v];
if(v >= (c[i]+1)/2){
res = max(res,dp[0][v-c[i]/2]+w[i]);
if(v >= c[i]){
res = max(res,dp[1][v-c[i]]+w[i]);
}
}
return res;
}

LL DP2(int i,int v){
LL res = dp[2][v];
if(v >= (c[i]+1)/2){
res = max(res,dp[1][v-c[i]/2]+w[i]);
if(v >= c[i]){
res = max(res,dp[2][v-c[i]]+w[i]);
}
}
return res;
}

void work(){
FOR(i,1,n+1){
IFOR(v,l,0){
dp[0][v] = DP0(i,v);
dp[1][v] = DP1(i,v);
dp[2][v] = DP2(i,v);
}
}
LL t = -1;
FOR(i,1,n+1)    t = max(t,(LL)w[i]);
printf("%lld\n",max(dp[2][l],t));
}

int main(){
//freopen("test.in","r",stdin);
int T,tCase = 0;    scanf("%d",&T);
while(T--){
printf("Case #%d: ",++tCase);
init();
work();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: