题目大意:给出n根筷子的长度和价值,最多可以装在一个长l的容器中,相邻筷子之间不允许重叠,且两边上的筷子,可以伸一半的长度在容器外,求最大价值量
解题思路:初看一眼就是01背包,没错就是01背包,但是有个特殊的地方需要处理,就是容器2边的筷子,将容器的长度X2,筷子的长度X2,那么相当于每根筷子的价值,可以被放0,1,2次,再加一层循环来枚举放筷子的价值量
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[4020][3];
struct Sticks
{
int l,v;
}sticks[1010];
int main()
{
int t,n,m;
scanf("%d",&t);
int cas = 1;
while(t--)
{
scanf("%d%d",&n,&m);
ll maxx = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d%d",&sticks[i].l,&sticks[i].v);
maxx = max(maxx,ll(sticks[i].v));
sticks[i].l *= 2;
}
m *= 2;
memset(dp,0,sizeof(dp));
for(int i = 1; i <= n; i++)
{
for(int j = m; j >= sticks[i].l/2; j--)
{
for(int k = 0; k <= 2; k++)///放入一半的筷子的数目
{
if(k >= 1)///已经有放入只装一半的筷子
dp[j][k] = max(dp[j][k],dp[j-sticks[i].l/2][k-1]+sticks[i].v);///当前筷子放入一半,或者不放入
if(j >= sticks[i].l)///放入整枝筷子
dp[j][k] = max(dp[j][k],dp[j-sticks[i].l][k]+sticks[i].v);
}
}
}
for(int i = 0; i <= 2; i++)
maxx = max(maxx,dp[m][i]);
printf("Case #%d: %lld\n",cas++,maxx);
}
return 0;
}