牛客多校第三场 A题 PACM Team

是我太菜,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
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值