关于背包问题动态规划代码的理解和应用

关于背包问题动态规划代码的理解和应用——

首先,关于背包问题动态规划的详细讲解在https://v.youku.com/v_show/id_XMTQ3MzI0NzI2OA==.html这个视频链接有详细的介绍,在此引用某位大神制作的视频表示感谢,同时也说声抱歉在我的博客引用视频没有直接取得同意。关于视频中那个外国的网页也给上https://www.merlot.org/merlot/viewMaterial.htm?id=1376786

好了废话不说,直接上代码

#include<stdio.h> 
#define N 6
#define M 21
int B[N][M]={0};//共5件物品,总重量是20
int w[6]={0,2,3,4,5,9};//物品重量分别是2,3,4,5,9
int v[6]={0,3,4,5,8,10};//物品价值分别是3,4,5,8,10
void knapsack(){
	int k,C;//第k个商品,C表示最大容量
	for(k=1;k<N;k++){
		for(C=1;C<M;C++){
			if(w[k]>C){
				B[k][C] = B[k-1][C];
			}//上面的if代码块执行当前物品的重量比背包容量大的情况
			/***其实背包问题最主要的是找到在偷第n个物品时,找到存放了n-1个物品的情况,而这个if代码块就是执行这样的操作***/
			else{
				int value1 = B[k-1][C-w[k]]+v[k];//偷这件物品
				/****注意这个是动态规划里面常用的操作方法***,C-w[k]是指偷了这个物品后容量减少w[k],偷了后价值就增加v[k]*/
				int value2 = B[k-1][C];//不偷这件物品
				if(value1>value2){
					B[k][C] = value1;
				}else{
					B[k][C] = value2;
				}
			}
		}
	} 
}
int main(){
	knapsack();
	printf("%d",B[5][20]);
}

背包问题的动态规划解法需要一个二维数组
在这里插入图片描述二维数组里第一行表示无物可取的时候value=0,第一列表示背包容量为0,第二行表示能偷的物品只有一件(value=3,weight=2的那件),第二列表示背包容量为1……以此类推
关于背包问题的详细说明视频里有解说这里就不再多说了,接下来说一下这种动态规划的应用问题——

最小邮票数(题目来源是牛客网)

  • 题目描述

    有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。 如,有1分,3分,3分,3分,4分五张邮票,要求凑成10分,则使用3张邮票:3分、3分、4分即可。

  • 输入描述:

    有多组数据,对于每组数据,首先是要求凑成的邮票总值M,M<100。然后是一个数N,N〈20,表示有N张邮票。接下来是N个正整数,分别表示这N张邮票的面值,且以升序排列。

  • 输出描述:

    对于每组数据,能够凑成总值M的最少邮票张数。若无解,输出0。

  • 示例1

输入
10
5
1 3 3 3 4
输出
3

解法说明:本题跟背包问题很相似,也是用动态规划去做,建立一个列数为11,行数为5的二维数组,上代码:

#include<stdio.h>
#define Max 100000
void bubble(int stamp[],int N){//用来进行冒泡排序的 
	int i,j;
	int temp;
	for(i=0;i<N;++i){
		for(j=0;j<N-i+1;++j){
			if(stamp[j]<stamp[j+1]){
				temp=stamp[j];
				stamp[j]=stamp[j+1];
				stamp[j+1]=temp;
			}
		}
	}
}
int main(){
	int N,M,i,j;//N是邮票数量,M是需要的总额 
	int stamp[20];//存储邮票值的数组
	int dp[20][100];//动态规划的二维数组 
	while(scanf("%d",&M)!=EOF){
		for(scanf("%d",&N),i=0;i<N;++i){
			scanf("%d",&stamp[i]);
		}
		bubble(stamp,N);
		/*上面是负责输入的操作,和对输入的数组进行排序*/
		for(i=0;i<N;++i){
			dp[i][0] = 0;//面值为0时直接是0,表格第【0】列全是0
		}
		for(j=0;j<=M;++j){
			if(j==stamp[0]){
				dp[0][j]=1;//面值只有1的时候,邮票只需要一张,也就是表格里面的第【1】列全是1
			}else{
				dp[0][j]=Max;
			}
		}
		/*上面是初始化操作的*/
		for(i=1;i<N;++i){
			for(j=1;j<=M;++j){
				dp[i][j]=dp[i-1][j];
				//这个if里面的就是动态规划最经典的操作 
				if(j>=stamp[i]&&dp[i][j]>dp[i-1][j-stamp[i]]+1){
					dp[i][j]=dp[i-1][j-stamp[i]]+1;
				}
			}
		}
		printf("%d",dp[N-1][M]<Max?dp[N-1][M]:0); 
	}
}

进行初始化操作后的表格——

最后的表格是——
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值