各种背包问题动态规划(C语言实现)

算法核心:

首先,需要设置一个二维数组t[][],其中t[i][j]表示利用前i个物品来装进容量为j的背包的所能够获得的最大价值。
当只考虑第i件物品时,可将情况分为是否放入第i件物品两种:
1.01背包——每个物品仅有一个
不放第i件物品:t[i][j]=t[i-1][j]
放入第i件物品:t[i][j]=t[i-1][j-weights[i]]+values[i]
2.完全背包——每个物品有无数个
不放第i件物品:t[i][j]=t[i-1][j]
放入第i件物品:t[i][j]=t[i][j-weights[i]]+values[i]
3.多重背包——每个物品数量有限
不放第i件物品:t[i][j]=t[i-1][j]
放入第i件物品:t[i][j]=t[i-1][j-k*weights[i]]+k*values[i]

注意:
(1)放入第i件物品的前提是当前空间j>=放入的物品的空间,即(j-weights[i]>=0或者j-k*weights[i]>=0);
(2)多重背包问题放入和不放入可以直接合为一种情况,即k的取值多一个k=0;
(3)对于t[][]数组一定要合理合适正确的进行初始化。对于找数值最大的问题,直接全部初始化为0即可;但是对于找数值最小的问题,在最开始需要将t数组全部初始化为一个超大值,然后并将t[0][0]初始为0;
(4)在这类题中,若有n类物品,一般从i=1开始进行对应,所以for循环一般为for(i=1;i<=n;i++);另一层表示空间的循环为for(j=0;j<=s;j++)。

实例以及代码

1.问题:有数量有限的几种面值的货币,要求用最少的张数凑成一个给定的总值。

2.实现代码

#define m 10000   //用于初始化数组
int t[30][30]={0},n,space; //n是种类,space是目标值
int weights[10];//面值
int values[10];//每一张的价值
int numbers[10];//每一种面值对应的数量
//处理输入
void Input(){
	int i;
	printf("纸币的种类数:");
	scanf("%d",&n);
	printf("对应纸币的面值:");
	for(i=1;i<=n;i++)
		scanf("%d",&weights[i]);
	printf("对应纸币的张数:");
	for(i=1;i<=n;i++)
		scanf("%d",&numbers[i]);
	for(i=1;i<=n;i++)
		values[i]=1;
	printf("期望凑的总面值:");
	scanf("%d",&space);
}
//数组t[][]初始化,这里是找最小值,于是往大了初始化
void Initialize(){  //全部初始化,只保留t[0][0]
	int i,j;
	for(i=0;i<=n;i++)
		for(j=0;j<=space;j++)
			t[i][j]=m;
	t[0][0]=0;
} 
//01背包
void ZeroOneBackpack(){
	int i,j,temp1,temp2=100;
	for(i=1;i<=n;i++)
		for(j=0;j<=space;j++)
		{
			temp1=t[i-1][j];//第i个不放
			if(j-weights[i]>=0)  //第i个放
				temp2=t[i-1][j-weights[i]]+values[i];
				if(temp1<temp2)
				t[i][j]=temp1;
			else
				t[i][j]=temp2;
		}
}
//完全背包
void CompletelyBackpack(){
	int i,j,temp1,temp2=100;
	for(i=1;i<=n;i++)
		for(j=0;j<=space;j++)
		{
			temp1=t[i-1][j];//第i个不放
			if(j-weights[i]>=0)  //第i个放
				temp2=t[i][j-weights[i]]+values[i]; 
			if(temp1<temp2)
				t[i][j]=temp1;
			else
				t[i][j]=temp2;
		}
}
//多重背包
void MultipleBackpack(){
	int i,j,temp,k,min;
	for(i=1;i<=n;i++)
		for(j=0;j<=space;j++)   //j也从0开始
		{
			min=m;
			for(k=0;k<=numbers[i];k++)
				if(j-k*weights[i]>=0)  //记得可以等于
				{
					temp=t[i-1][j-k*weights[i]]+k*values[i]; 
					if(temp<min)
						min=temp;
				}
			t[i][j]=min;
		}
}
//输出结果
void Output(){
	printf("最小的凑齐张数:%d\n",t[n][space]);
}
int main(){
	Input();
	//每次都要初始化一下数组t[][]
	Initialize();
	ZeroOneBackpack();
	printf("0-1背包");
	Output();
	
	Initialize();
	CompletelyBackpack();
	printf("完全背包");
	Output();
	
	Initialize();
	MultipleBackpack();
	printf("多重背包");
	Output();
	return 0;
}

3.运行结果
在这里插入图片描述

原创文章 16 获赞 5 访问量 997

猜你喜欢

转载自blog.csdn.net/qq_42453280/article/details/106092833