**问题表述:**
容量为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");
}
}