这是道完全背包,关键点在于如何处理每种物品,第一次放时,价值为A+B,以后放时,价值为A。
所以有三种决策,对于第i种物品,要么不放,要么是作为第一个放,要么是第二个以后放。
作为第一个放时,需要用到上一行的状态,所以需要增加一个状态表示上一行的状态。
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #define maxn 300000 #define LL long long using namespace std; int V[maxn],A[maxn],B[maxn]; int d[maxn]; //d[j]代表容量为j的背包,处理到第i种物品时的最大值 int p[maxn]; //p[j]代表容量为j的背包,处理到上一行物品的最大值 int M,N; void init() { memset(d,0,sizeof(d)); memset(p,0,sizeof(p)); } void solve() { for(int i=1;i<=N;i++) { for(int j=V[i];j<=M;j++) { d[j]=max(d[j-V[i]]+A[i],d[j]); //要么不是第一个放 d[j]=max(p[j-V[i]]+A[i]+B[i],d[j]); //要么是第一个放 } for(int j=0;j<=M;j++) { p[j]=d[j]; } } int ans=0; for(int j=0;j<=M;j++) ans=max(ans,d[j]); printf("%d ",ans); } int main() { //freopen("test.txt","r",stdin); int t; scanf("%d",&t); while(t--) { init(); scanf("%d%d",&M,&N); for(int i=1;i<=N;i++) { scanf("%d%d%d",&V[i],&A[i],&B[i]); } solve(); } return 0; }
第一次做时陷入了一个误区,就是说d[j]=max(d[j-V[i]]+W[i],d[j]);,我想的是用一个数组来记录容量为j的背包能够取得的最大价值的隐含的序列是否放过i种物品,
如果是第一次放,那么W[i]=A+B,如果是第二次放,那么W[i]=A;
可是没有考虑到对于第i种物品,每种容量都有放0,1,一个以上的权利,
但是这样考虑的话,写的时候,就写成了下面这个样子,如果j-V[i]放过的话,那么j容量就只能不放,或者放2个以上。
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #define maxn 300000 #define LL long long using namespace std; int V[maxn],A[maxn],B[maxn]; int d[maxn]; int M,N; int visit[maxn]; void init() { memset(d,0,sizeof(d)); } void solve() { for(int i=1;i<=N;i++) { memset(visit,0,sizeof(visit)); int t=0; for(int j=V[i];j<=M;j++) { if( visit[j-V[i]]==0) //如果之前没有放过 { if(d[j-V[i]]+A[i]+B[i]>=d[j]) //加上A+B { d[j]=d[j-V[i]]+A[i]+B[i]; visit[j]=1; } } else //如果放过,加上A { // if(j==M) // printf("d[j]: %d d[j-V[i]] %d V[i] %d ",d[j],d[j-V[i]],V[i]); if(d[j-V[i]]+A[i]>=d[j]) { d[j]=d[j-V[i]]+A[i]; visit[j]=1; } } // d[j]=max(d[j-V[i]]+A[i]+B[i],d[j]); printf("%d ",d[j]); t++; if(t%5==0) printf(" "); } printf(" "); } printf("%d ",d[M-1]); } int main() { freopen("test.txt","r",stdin); int t; scanf("%d",&t); while(t--) { init(); scanf("%d%d",&M,&N); for(int i=1;i<=N;i++) { scanf("%d%d%d",&V[i],&A[i],&B[i]); } solve(); } return 0; }