是我太菜,01背包不知道怎么记录状态,一开始浪费好久时间,然后发现记录了以后int数组开不下,我并没有想到可以使用short来存,5维dp数组还是超过256mb,于是最后同机房好友提醒我使用bool数组来存dp更新的时候的是否使用了当前的i号物品
#include<bits/stdc++.h>
#define X first
#define Y second
#define pb push_back
#define mk make_pair
#define rep(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
typedef long long LL;
const int maxn=37;
int n,m,ccnt;
int a[maxn][6];
int b[5];
int dp[maxn][maxn][maxn][maxn];
bool used[maxn][maxn][maxn][maxn][maxn];
int res[5],anss[maxn];
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;++i)
for(int j=1;j<=5;++j)
scanf("%d",&a[i][j]);
for(int i=1;i<=4;++i)
scanf("%d",&b[i]);
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;++i)
{
/*for(int j=b[1];j>=0;--j)
for(int k=b[2];k>=0;--k)
for(int l=b[3];l>=0;--l)
for(int r=b[4];r>=0;--r)
used[i][j][k][l][r]=used[i-1][j][k][l][r];*/
memset(used[i],0,sizeof(used[i]));
for(int j=b[1];j>=a[i][1];--j)
for(int k=b[2];k>=a[i][2];--k)
for(int l=b[3];l>=a[i][3];--l)
for(int r=b[4];r>=a[i][4];--r)
if(dp[j][k][l][r]<dp[j-a[i][1]][k-a[i][2]][l-a[i][3]][r-a[i][4]]+a[i][5])
{
dp[j][k][l][r]=dp[j-a[i][1]][k-a[i][2]][l-a[i][3]][r-a[i][4]]+a[i][5];
used[i][j][k][l][r]=true;
}
}
anss[0]=0;
for(int i=1;i<=4;i++)
res[i]=b[i];
for(int i=n;i>=1;i--)
if(used[i][res[1]][res[2]][res[3]][res[4]])
{
anss[++anss[0]]=i;
res[1]-=a[i][1];res[2]-=a[i][2];res[3]-=a[i][3];res[4]-=a[i][4];
}
ccnt=anss[0];
printf("%d\n",ccnt);
if(ccnt>0)
{
for(int i=1;i<anss[0];i++)
printf("%d ",anss[i]-1);
printf("%d\n",anss[anss[0]]-1);
}
else
printf("\n");
}
return 0;
}
/*
2
1 0 2 1 10
1 0 2 1 21
36 36 36 36
1
2 1 1 0 31
1 0 2 1
2
1 0 2 1 10
1 0 2 1 21
1 0 2 1
2
1 0 2 1 10
1 0 2 1 21
36 36 36 36
1
2 1 1 0 31
1 0 2 1
2
1 0 2 1 10
1 0 2 1 21
1 0 2 1
for(int i=n;i>=1;i--)
if(res[1]>=a[i][1] &&res[2]>=a[i][2] &&res[3]>=a[i][3] &&res[4]>=a[i][4])
if(dp[i][res[1]][res[2]][res[3]][res[4]]==
dp[i-1][res[1]-a[i][1]][res[2]-a[i][2]][res[3]-a[i][3]][res[4]-a[i][4]]+a[i][5])
{
anss[++anss[0]]=i;
res[1]-=a[i][1];res[2]-=a[i][2];res[3]-=a[i][3];res[4]-=a[i][4];
}
*/
赛后询问了一波aols,发现aols一波找答案的容量最小值,然后fori=n;i>=1去判断是否更新了dp[i],就巨强无比,先把0 0 0 0 g[i]的点先拿出来,这样保证了一定是从dp[0][0][0][0]转移过来的,而且一定是放满那些容量的,这样就优化掉了一维空间,%aols
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 37
using namespace std;
int p[maxn],a[maxn],c[maxn],m[maxn],g[maxn];
int dp[maxn][maxn][maxn][maxn],use[maxn];
int n,P,A,C,M;
vector <int> mem;
int main(){
scanf("%d",&n);
int cnt=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d%d",&p[i],&a[i],&c[i],&m[i],&g[i]);
if(p[i]==0&&a[i]==0&&c[i]==0&&m[i]==0)
{
mem.push_back(i);
use[i]=1;
}
}
scanf("%d%d%d%d",&P,&A,&C,&M);
dp[0][0][0][0]=0;
for(int i=1;i<=n;i++){
if(use[i]==1) continue;
for(int j=P;j>=0;j--)
for(int k=A;k>=0;k--)
for(int t=C;t>=0;t--)
for(int l=M;l>=0;l--)
if(j>=p[i] && k>=a[i] && t>=c[i] && l>=m[i]){
if(dp[j][k][t][l]<dp[j-p[i]][k-a[i]][t-c[i]][l-m[i]]+g[i]){
dp[j][k][t][l]=dp[j-p[i]][k-a[i]][t-c[i]][l-m[i]]+g[i];
}
}
}
int ans=0,l1=P,l2=A,l3=C,l4=M;
for(int j=P;j>=0;j--)
for(int k=A;k>=0;k--)
for(int t=C;t>=0;t--)
for(int l=M;l>=0;l--)
if(dp[j][k][t][l]>=ans){
l1=j; l2=k; l3=t; l4=l;
ans=dp[j][k][t][l];
}
//printf("%d %d\n",dp[10][2][2][2],dp[4][4][4][4]);
/*for(int i=1;i<=n;i++)
if(p[i]==0 && a[i]==0 && c[i]==0 && m[i]==0 && g[i]!=0)
{
use[i]=1,mem.push_back(i);
}*/
while(1){
int t=233;
for(int i=1;i<=n;i++)
if(!(p[i]==0 && a[i]==0 && c[i]==0 && m[i]==0) && !use[i] && l1>=p[i] && l2>=a[i] && l3>=c[i] && l4>=m[i] && dp[l1][l2][l3][l4]==dp[l1-p[i]][l2-a[i]][l3-c[i]][l4-m[i]]+g[i]){
use[i]=1; t=i; break;
}
if(t==233) break;
mem.push_back(t);
l1-=p[t]; l2-=a[t]; l3-=c[t]; l4-=m[t];
}
printf("%d\n",mem.size());
for(int i=0;i<mem.size();i++)
printf("%d ",mem[i]-1);
return 0;
}
/*
4
0 0 0 0 2
2 2 2 2 3
0 0 0 0 1
2 2 2 2 4
10 10 10 10
*/