您的位置:首页 > 其它

hdu5410(完全背包变形)

2015-08-21 10:54 239 查看
这是道完全背包,关键点在于如何处理每种物品,第一次放时,价值为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\n",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\n",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("\n");
}
printf("\n\n");
}
printf("%d\n",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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: