该题是15年CCPC的D题,背包变形,昨天队内组队赛和队友搞了出来 。 各种超时,能优化的地方都搞了才勉强过,应该是姿势不太对。
与普通背包唯一的不同之处就是该题的木板可以超出桌面,只要重心在桌面上就行,那么最多只有两个木板超出桌面,那么不妨尽量多的超出(一半在桌子上),为其他木板留出更大的空间。 这样我们就必须增加一维,表示超出桌面的木板个数。 对于每个木板有两种决策:选还是不选。对于选的木板又有两种决策:是否放在边上让其一半超出桌面。
细节参见代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const double eps = 1e-6;
const int INF = 1000000000;
const int maxn = 1000 + 5;
const int maxl = 2000 + 5;
int T,n,m,kase=0;
ll d[2][2*maxl][3],w[maxn],v[maxn],L;
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d%lld",&n,&L);
L *= 2;
ll ans = 0, u = 0;
for(int i=0;i<=L;i++)
for(int k=0;k<3;k++) d[0][i][k] = 0;
for(int i=1;i<=n;i++) {
scanf("%lld%lld",&w[i],&v[i]), w[i] *= 2;
ans = ans>v[i]?ans:v[i];
for(ll j=0;j<=L;j++) {
for(int k=0;k<=2;k++) {
d[1-u][j][k] = d[u][j][k];
if(k > 0 && j >= (w[i]>>1)) d[1-u][j][k] = (d[1-u][j][k]>d[u][j-(w[i]>>1)][k-1]+v[i])?d[1-u][j][k]:d[u][j-(w[i]>>1)][k-1]+v[i];
if(j >= w[i]) d[1-u][j][k] = (d[1-u][j][k]> d[u][j-w[i]][k]+v[i])?d[1-u][j][k]: d[u][j-w[i]][k]+v[i];
}
}
u = 1-u;
}
ans = (d[u][L][0]>ans)?d[u][L][0]:ans;
ans = (d[u][L][1]>ans)?d[u][L][1]:ans;
ans = (d[u][L][2]>ans)?d[u][L][2]:ans;
printf("Case #%d: %lld\n",++kase,ans);
}
return 0;
}