动态规划(3)

本来这次是要学习字符串的最短编辑距离的,但是由于最近正在研究《linux服务器高性能编程》以及实验室项目验收,所以没有时间对这个进行深入理解,所以暂时搁置一段时间,这次来学习一下0-1背包问题,以及找零问题。对于这两个问题都属于动态规划的经典问题。

0-1背包问题:

假如有容量为10(克)的包和重量为3,4,5(克)的物品,每件物品的价值为4,5,6.先求在容量不超过10克的情况下,包中物品的总价值最高。

找零问题:

假如收银员需要给顾客找26块钱现在,有面值1,2,3,21,25币钞(每种币钞的数量无限),现在如何选择才能使使用的币钞个数最少。


我们先来分析找零问题.既然是动态规划,那么必须会要求我们找出子问题,以及使用数组存储子问题。题目要求我们找出26块钱使用的最少,那我们的子问题就是25,24......到1,每种情况所使用的币钞的最少数量,所以我们需要大小为26的数组存储中间过程。我们的递归方程描述为,MinTemp=min(MinTemp,coins[i - value[j] + 1),MinTemp是我们使用的最少硬币的个数,value数组是我们存储面值的数组即 1,2,3,21,25(每种面值的货币数量无限)。coins数组存储MinTemp,如coins[4]表示构造面值为4的货币需要的最少币钞数。这样我们再来看一下coins[i - value[j]] + 1,其表示当我们构造值为i的货币时,如果我们要用value[j]中所存储的那个货币,那么我们需要知道构造 i - value[j]所需要的最小货币数,再加value【j】(就是后面那个1),这样我们每次取最小存储在MinTemp,最后将其存在coins[i],当然在计算前我们必须满足i - value[j] >0.下面我们来给出实现代码。

#include<stdio.h>
#define VALUE 105

#define Size  5


const value[] = {1,2,5,21,25};
int coinsUsed[VALUE] = {0};
int coinsTrack[VALUE] = {0};

void MakeChange()
{
	int i,j;
	int coinvalues = 0;
	

	for(i = 1; i<VALUE; i++)
	{
		int MinTemp = VALUE;
		
		for(j = 0; j<Size; j++)
		{
			if(i >= value[j] )      //如果i < value[j] 那么我们肯定不能用value【j】就好像1钱不可能用两块钱来找吧
			{
				if(MinTemp >= coinsUsed[i - value[j]])  
				{
					 MinTemp =coinsUsed[i - value[j]];
					 coinvalues = value[j];
				}
			}
		}
		
		coinsUsed[i] = MinTemp + 1;
		coinsTrack[i] = coinvalues;    //该数组用于存储所运用货币
	}
}

int main()
{
	int i = 0;
	MakeChange();
	for(i = 1; i < VALUE; i++)
		printf("%d ",coinsUsed[i]);
	printf("\n");
		
	int temp = VALUE-1;
	while(temp > 0)
	{
		printf("%d ", coinsTrack[temp]);     //输出所用的货币
		temp = temp - coinsTrack[temp];
	}
	printf("\n");
		
	
}
	

对于0-1背包问题如果我们不限物品的个数,那么那么我们的问题就和上述问题没什么区别,只不过将上述加1改成该物品的价值price【i】,再做稍微的调整。对于每件物品只有一件,那么就不能使用上述动态方程。我们的动态方程变为

c[i][j] = MAX(c[i-1][j], c[i][j-weight[i] + price[j]).


上述图片是我从我网上找到的一幅图很好的解释图片,下面我来做一下解释。

上图j表示背包的容量,i表示物品的下标,也就是物品的重量weight的下标。c[i][j]表示将有i个物品,背包容量为j时最大价值。

MAX(c[i-1][j], c[i -1][j -weight[i]]+price[i]).其表示如果我们不用第i个物品那么容量为j的物品的最大价值为c[i -1][j],如果我们要用第j个物品那么其价值为c[i-1][j - weight[i]] + price[i],j - weight[i]表示如果我们要用weight【i】那么我们还需知道容量为j - weight[i]的最大价值(实际编程时注意给下标从0开始)。

#include<stdio.h>
#define MAX(a,b) (((a) > (b))? (a) : (b))

int c[4][11] = {0};    //用于存储packet1的最大价值数组(当每件物品只有一个时)
int USED[11] = {0};	//用于packet2的最大价值数组(每件物品有多个是,类似于找零问题)
int w[3] = {3,4,5};		//物品重量
int price[4] = {4,5,6};     //物品价值

void packet1(int N, int CONTATINER)    //每件物品只有一个时
{
	int i, j;
	for(i =1; i < N + 1; i++)
	{
		for(j = 1; j < CONTATINER + 1; j++)
		{
			if(w[i-1] <= j)
				c[i][j] = MAX(c[i-1][j], c[i-1][j-w[i-1]] + price[i-1]);
			else
			 	c[i][j] = c[i-1][j]; 
		}
	}
}



void packet2(int N, int CONTATINAER)  //每件物品有多个时
{
	
	int temp ;
	int i, j;
	for(i =1; i < N + 1; i++)
	{
		temp = 0;
		for(j = 0; j < CONTATINAER; j++)
		{
			if(i >= w[j])
			{
				if(temp < USED[i-w[j]] + price[j])
					temp = USED[i - w[j]] + price[j];
			}
			
		}
		USED[i] = temp;
	}
}

int main()
{
	int i;
	int j;
	packet2(10,3);
	for(i =0; i < 10 + 1; i++)
		printf("%d ", USED[i]);
		printf("\n");

	printf("_______________________________________\n");
	packet1(3, 10);
	for(i = 0; i < 4; i++)
	for(j = 0; j < 11; j++)
	{
		printf("%d ", c[i][j]);
		if(j==10)
			printf("\n");
	}

}
		
	
	
		



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值