题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5543
题意:有长度为 len 的容器,有n种木棍,每种木棍有对应的长度和价值,容器上可以放木棍,不能重叠,如果在容器的两边,只要木棍的重心在容器内就能放的上,问最后能放的最大价值;
/*
做DP,要先想数组每一维代表着什么,然后想转移方程
dp[i][j][k],当前处理到第 i个木棍,枚举长度,有k个悬挂在外面;
第一维可以省去,只需要让 j 降序就行了
dp[j][k]=max(dp[j][k],dp[j-q[i].a][k]+q[i].v);
dp[j][k]=max(dp[j][k],dp[j-q[i].h][k-1]+q[i].v);
处理木棍长度的重心,可能会出现小数,让长度全部乘2;
*/
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<string>
#include<iostream>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
const int N=4e3+10;
struct node
{
int a,h;
ll v;
}q[1005];
ll dp[N][3];
bool cmp(node x,node y)
{
if(x.a!=y.a) return x.a<y.a;
}
ll ll_max(ll a,ll b)
{
if(a>b) return a;
return b;
}
int main()
{
int T,cas=0;
scanf("%d",&T);
while(T--)
{
memset(dp,0,sizeof(dp));
int n,len;
ll ans=0;
scanf("%d %d",&n,&len);
len*=2;
for(int i=1;i<=n;i++)
{
scanf("%d %lld",&q[i].a,&q[i].v);
q[i].h=q[i].a;
q[i].a*=2;
ans=ll_max(ans,q[i].v);
}
sort(q+1,q+n+1,cmp);
while(n>=1&&q[n].h>=len) --n;//优化一下,将一半长度都大于容器长度的去掉
for(int i=1;i<=n;i++)
{
for(int j=len;j>=q[i].h;j--)
{
for(int k=0;k<3;k++)
{
if(j>=q[i].a) dp[j][k]=max(dp[j][k],dp[j-q[i].a][k]+q[i].v);
if(k) dp[j][k]=max(dp[j][k],dp[j-q[i].h][k-1]+q[i].v);
}
}
}
ans=max(ans,dp[len][2]);
printf("Case #%d: %lld\n",++cas,ans);
}
return 0;
}