【9926】完全背包

Time Limit: 1 second
Memory Limit: 128 MB

【问题描述】

设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为M,今从n种物品中
选取若干件(同一种物品可以多次选取),使其重量的和小于等于M,而价值的和为最大。

【输入格式】

第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);
第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。

【输出格式】

仅一行,一个数,表示最大总价值。

Sample Input

10 4
2  1
3  3
4  5
7  9
【题解】
【法一】
设f[i][j]表示前i个物品,所用的容量不超过j所能获得的最大价值。
f[i][j] = max{f[i-1][j],f[i-1][j-k*w[i]] + k*c[i]}; (k*w[i] <=j)
对于第i个物品,可以选择不拿(f[i-1][j]),也可以任意选择k个。
这种二维的存储方式比较容易理解。
#include <cstdio>
#include <cstring>

int m,n,f[31][250],w[50],c[50];

void input_data()
{
	scanf("%d%d",&m,&n);
	for (int i = 1;i <= n;i++) //êäèë¸÷¸öÎïÆ·μÄDÅÏ¢ 
		scanf("%d%d",&w[i],&c[i]);
}	

void get_ans()
{
	memset(f,0,sizeof(f));			 
	for (int i = 1;i <= n;i++)
		for (int j = m;j >= 0;j--)
			{
				f[i][j] = f[i-1][j];
				int k = 1;
				while (k*w[i] <= j)
					{
						if (f[i][j] < f[i-1][j-k*w[i]] + k*c[i])
							f[i][j] = f[i-1][j-k*w[i]] + k*c[i];
						k++;
					}
			}
}

void output_ans()
{
	printf("max=%d",f[n][m]);	
}

int main()
{
	//freopen("F:\rush.txt","r",stdin);
	input_data();
	get_ans();
	output_ans();
	return 0;	
}
【法二】
设f[j]表示容量不超过j的背包所能装得的最大价值。
f[j] = max{f[j],f[j-w[i]] + c[i]};
这次j层循环要正向进行。
假设一个物品的重量为1.
你更新完f[5],又可以更新f[6],f[7]...这样就达到了每个物品可以多次拿的效果。
#include <cstdio>
#include <cstring>

int m,n,f[250],w[50],c[50];

void input_data()
{
	scanf("%d%d",&m,&n);
	for (int i = 1;i <= n;i++) 
		scanf("%d%d",&w[i],&c[i]);
}	

void get_ans()
{
	memset(f,0,sizeof(f));			 
	for (int i = 1;i <= n;i++)
		for (int j = w[i];j <= m;j++) //一定要正向循环。 
			if (f[j-w[i]] + c[i] > f[j]) //这里就省掉了一层k循环。 
				f[j] = f[j-w[i]] + c[i];
}

void output_ans()
{
	printf("max=%d",f[m]);	
}

int main()
{
	//freopen("F:\rush.txt","r",stdin);
	input_data();
	get_ans();
	output_ans();
	return 0;	
}




原文地址:https://www.cnblogs.com/AWCXV/p/7632395.html