背包问题(二):0-1背包

**问题表述:**

容量为V的背包,N件物品,每个一个, 价格ci, 利润wi;

在不超过容量的前提下,使得利润最高

用profit[v]表示容量为v的背包中放了物品后的最大利润; 那么 profit[v] = max{profit[v], profit[v-ci]+wi};

如果当前物品(第i个物品)放进去了的话,就是profit[v-ci]+wi; 没放进去的话就是profit[v](还是之前的状态没有变化);

这里 profit[v] = max{profit[v], profit[v-ci]+wi};中第一个profit[v]表示当前容量为v的背包的最大利润,而max比较的都是上一个状态(在完全背包问题中,比较的是当前状态),所以要用逆序表示

for(int i = 0; i <N;i++)

for(int j = V; j>=ci;j--)

profit[j] = max{profit[j] , profit[j-ci]+wi }

//其实只要想想,变成正序的话正着加会使得一个物品加很多遍 p[1] = w1; p[2] = p[1]+w1...但是逆序就只会每个加一遍 p[4] = p[3]+w1(p3 此时还是0); p[3] = p[2]+w1 = w1; p[2] = p[1] +w1 = w1; p[1] = w1; 这样不会有一个物品重复加的情况



**例题:** 

P本金, N个物品,每个物品限买一个,每个物品的价格ci, 利润wi; 不过是使得在本金必须花完的情况下获得的最大利润,如果无法花完本金,输出jpx;分析:还是上面的0-1背包问题,只不过要求背包一定要装满。这样在初始化背包(profit)的时候可以全部初始成-1 ,开始时只有profit[0] = 0;其他的0都是不合法的。比较的时候只要探讨一下profit[j-w]是不是已经装满了(==-1)即可

代码样例:

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cstring>

using namespace std;

int profit[21005];

int main()

{  

int P,N,p,c;

while(~scanf("%d%d",&P,&N))

{ memset(profit,-1,sizeof(profit));

profit[0] = 0;

for(int i = 0;i<N;i++)

{ scanf("%d%d",&p,&c);

for(int j = P;j>=c;j--)

{  

if(profit[j-c]!=-1&&profit[j]<profit[j-c]+p)

profit[j] = profit[j-c]+p;  

}  

}  

if(profit[P]!=-1)

printf("%d\n",profit[P]);

else printf("jpx\n");

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值