完全背包(CompletePack)
有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
完全背包按其思路仍然可以用一个二维数组来写出:
f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v}
问题来源:题目
3 10 110 2 1 1 30 50 10 110 2 1 1 50 30 1 6 2 10 3 20 4
The minimum amount of money in the piggy-bank is 60. The minimum amount of money in the piggy-bank is 100. This is impossible.
同样可以转换成一维数组来表示:
伪代码如下:
for i=1..N
for v=0..V
f[v]=max{f[v],f[v-c[i]]+w[i]}
想必大家看出了和01背包的区别,这里的内循环是顺序的,而01背包是逆序的。
现在关键的是考虑:
为何完全背包可以这么写?
我们先来回忆下,01背包逆序的原因?是为了是max中的两项是前一状态值,这就对了。
那么这里,我们顺序写,这里的max中的两项当然就是当前状态的值了,为何?
因为每种背包都是无限的。
当我们把i从1到N循环时,f[v]表示容量为v在前i种背包时所得的价值,这里我们要添加的不是前一个背包,而是当前背包。所以我们要考虑的当然是当前状态。
C/C++版:
#include<stdio.h>
int num[10001],w[500],v[500];
main()
{
int n,m,e,f,t,i,j;
for(scanf("%d",&t);t>0;t--)
{
scanf("%d%d",&e,&f);
m=f-e;
for(scanf("%d",&n),i=0;i<n;i++)
scanf("%d%d",&v[i],&w[i]);
num[0]=0;
for(i=1;i<=m;i++)
num[i]=-1;
for(i=0;i<n;i++)
{
for(j=w[i];j<=m;j++)
{
if(num[j-w[i]]!=-1&&num[j]!=-1)
{if(num[j-w[i]]+v[i]<num[j]) num[j]=num[j-w[i]]+v[i];}
else if(num[j-w[i]]!=-1&&num[j]==-1)
{num[j]=num[j-w[i]]+v[i];}
}
}
if(num[m]!=-1)
printf("The minimum amount of money in the piggy-bank is %d.\n",num[m]);
else
printf("This is impossible.\n");
}
}
java版:
public static void main(String[] args) throws IOException {
int nCases=0;
int nPack, nVolume1, nVolume2, nVolume;
int weight[]= new int[510];
int value[] = new int[510];
int record[]= new int[1000];
int INF = 1000000001;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String read = null;
System.out.print("输入数据:");
try {
read = br.readLine();
nCases = Integer.valueOf(read);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("输入的数据:"+read);
while(nCases-->0)
{
nVolume1 = Integer.valueOf(br.readLine());
nVolume2 = Integer.valueOf(br.readLine());
nVolume = nVolume2-nVolume1;
nPack = Integer.valueOf(br.readLine());
System.out.println("npack:" + nPack);
for(int i=0; i<nPack; ++i)
{
value[i] = Integer.valueOf(br.readLine());
System.out.println("value[i]" + value[i]);
weight[i] = Integer.valueOf(br.readLine());
System.out.println("weight[i]" + weight[i]);
}
for(int i=0; i<=nVolume; ++i)
record[i] = INF;
record[0] = 0;
for(int i=0; i<nPack; ++i)
for(int j=weight[i]; j<=nVolume; ++j)
if(record[j]>record[j-weight[i]]+value[i])
record[j] = record[j-weight[i]]+value[i];
if(record[nVolume] == INF)
System.out.println("This is impossible.\n");
else
System.out.println("The minimum amount of money in the piggy-bank is " + record[nVolume]);
}
}