背包问题

背包问题

. 0/1 背包问题

题目

01背包问题描述:有编号分别为a,b,c,d,e的五件物品,
它们的重量分别是2,2,6,5,4,
它们的价值分别是6,3,5,4,6,
每件物品数量只有一个,
现在给你个承重为c=10的背包,如何让背包里装入的物品具有最大的价值总和?

思路
代码
int knapsack_01(vector<int>&W, vector<int>&V, int C){ 
       if (W.size() != V.size()) return -1; 
       if (W.size() < 1 || V.size() < 1 || C < 0) return -1; 
       //开辟动态规划的空间,dp[i][cc] 表示使用前i个硬币,放入容量为c的背包的最大价值 
       int n = W.size();          //商品种类 
       vector<vector<int>> dp(n, vector<int>(C+1 , 0));              //【n,c+1]大小的矩阵 
       //初始化第一行,第一列 
       //第一行表示,只使用商品1,放入容量为1,2,....c的包中的最大价值 
       for (int cc = 0;cc <= C; cc++){ 
              if (W[0] <=cc) 
                     dp[0][cc] = V[0]; 
       } 
       第一列表示,使用商品1,2,...,商品放入容量为0的包最大价值,都为0,已经初始化为0了,不用重复操作 
       //for (int i = 0; i < n; i++){  
       //            dp[i][0] = 0; 
       //} 
 
       //递推 
       /*   
              选择第i个商品,  则s1 = dp[i-1][cc-wi]+vi 
              不选择第i个商品,则s2 = dp[i-1][cc] 
              dp[i][cc] =max(s1,s2);                   //选择最优 
       */
 
       for (int i = 1; i < n; i++){ 
              for (int cc = 1; cc <= C; cc++){  
              //因为内层遍历的包的大小从1到C连续编号,对于某个商品wi来说,可能包的容量cc比较小的时候,是没法放入容量为cc的包的,只能不选择第i个商品,则s = dp[i-1][cc] 
                     if (W[i] >cc){ 
                           dp[i][cc] = dp[i - 1][cc]; //放不小,则不放入 
                     } 
                     else{ 
                           dp[i][cc] = max(dp[i - 1][cc],  
                                                dp[i - 1][cc - W[i]] + V[i]);  //能放入,则决策是否要真的要放入 
                     } 
              } 
       }  
       //打印观察 
       for (int i = 0; i < dp.size(); i++){ 
              printf("使用前%d个商品:",i); 
              for (int j = 0; j < dp[0].size(); j++){ 
                     printf("%4d ", dp[i][j]);  
              } 
              printf("\n"); 
       } 
       //返回最后结果  
       return dp[n - 1][C]; 
} 

.完全背包问题

题目

完全背包问题:
完全背包问题描述:有编号分别为a,b,c,d的四件物品,
它们的重量分别是2,3,4,7,
它们的价值分别是1,3,5,9,
每件物品数量无限个,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?

思路
代码
int knapsack_complete(vector<int>&W, vector<int>&V, int C){
	if (W.size() != V.size()) return -1;
	if (W.size() < 1 || V.size() < 1 || C < 0) return -1; 

	//开辟动态规划的空间,dp[i][cc] 表示使用前i个硬币,放入容量为c的背包的最大价值

	int n = W.size();		//商品种类
	vector<vector<int>> dp(n, vector<int>(C + 1, 0));		//【n,c+1]大小的矩阵

	//初始化第一行,第一列
	//第一行表示,只使用商品1,放入容量为1,2,....c的包中的最大价值
	for (int cc = 0; cc <= C; cc++){ 
			dp[0][cc] = (cc / W[0])*V[0];      //商品1可以重复使用,重复个数为cc/W[0]
	}


	第一列表示,使用商品1,2,...,商品放入容量为0的包最大价值,都为0,已经初始化为0了,不用重复操作
	//for (int i = 0; i < n; i++){ 
	//		dp[i][0] = 0;
	//}


	//递推
	/*
	选择第i个商品,  则s1 = dp[i][cc-wi]+vi     //注意dp[i]和完全背包中的dp[i-1]不同,使用dp[i]表示即使当前行中已经使用的背包i,在该行中仍然可以继续使用
	不选择第i个商品,则s2 = dp[i-1][cc]
	dp[i][cc] =max(s1,s2);			//选择最优
	*/

	for (int i = 1; i < n; i++){
		for (int cc = 1; cc <= C; cc++){
			//因为内层遍历的包的大小从1到C连续编号,对于某个商品wi来说,可能包的容量cc比较小的时候,是没法放入容量为cc的包的,只能不选择第i个商品,则s = dp[i-1][cc]
			if (W[i] >cc){
				dp[i][cc] = dp[i - 1][cc];	//放不小,则不放入
			}
			else{
				dp[i][cc] = max(dp[i - 1][cc],
								dp[i    ][cc - W[i]] + V[i]);  //能放入,则决策是否要真的要放入,当前行中比较,表示可以重复使用
			}
		}
	}
 

	//打印观察
	for (int i = 0; i < dp.size(); i++){
		printf("使用前%d个商品:", i);
		for (int j = 0; j < dp[0].size(); j++){
			printf("%4d ", dp[i][j]);
		}
		printf("\n");
	}
 
	//返回最后结果 
	return dp[n - 1][C];

}


.多重背包问题

题目

多重背包问题:
多重背包问题描述:
有编号分别为a,b,c的三件物品,
它们的重量分别是1,2,2,
它们的价值分别是6,10,20,
他们的数目分别是10,5,2,现在给你个承重为 8 的背包,如何让背包里装入的物品具有最大的价值总和?

思路

多重背包和01背包、完全背包的区别:多重背包中每个物品的个数是有限的。

初始化时,
只考虑一件物品a时,
count = min{num[1], cc/weight[1]}。
f[1][cc] = count* v[1];
计算考虑i件物品承重限制为y时最大价值f[i][cc]时,递推公式考虑两种情况,
要么第 i 件物品一件也不放,就是f[i-1][cc],
要么第 i 件物品放 k 件,其中 1 <= k <= count, 其中count=min{num[i], cc/weight[i]}
考虑这一共 k+1 种情况取其中的最大价值即为f[i][y]的值,
即f[i][cc] = max{f[i-1][cc],
f[i-1][cc-kweight[i]]+kvalue[i]}。

代码

int knapsack_multi(vector<int>&W, vector<int>&V, vector<int>&N, int C){
	if (W.size() != V.size()) return -1;
	if (W.size() < 1 || V.size() < 1 || C < 0) return -1; 

	//开辟动态规划的空间,dp[i][cc] 表示使用前i个硬币,放入容量为c的背包的最大价值 
	int n = W.size();		//商品种类
	vector<vector<int>> dp(n, vector<int>(C + 1, 0));		//【n,c+1]大小的矩阵 
	//初始化第一行,第一列
	//第一行表示,只使用商品1,放入容量为1,2,....c的包中的最大价值 
	for (int cc = 0; cc <= C; cc++){
		int count = min(cc / W[0], N[0]);    //商品1可以重复使用,重复个数在cc/W[0]和总个数N[0]中取最小值
		dp[0][cc] = (count)*V[0];
	} 
	第一列表示,使用商品1,2,...,商品放入容量为0的包最大价值,都为0,已经初始化为0了,不用重复操作
	//for (int i = 0; i < n; i++){ 
	//		dp[i][0] = 0;
	//}


	//递推
	/*
	要么第 i 件物品一件也不放,就是f[i-1][cc],
	要么第 i 件物品放 k 件,其中 1 <= k <= count, 其中count=min{num[i], cc/weight[i]}
		考虑这一共 k+1 种情况取其中的最大价值即为f[i][y]的值,
		即f[i][cc] = max{f[i-1][cc],
						f[i-1][cc-k*weight[i]]+k*value[i]}。
	*/

	for (int i = 1; i < n; i++){
		for (int cc = 1; cc <= C; cc++){
			if (W[i]>cc){						//一个都放不下的时候
				dp[i][cc] = dp[i - 1][cc];
			}
			else                                       //能放下多个的时候
			{
				int count = min(cc / W[i], N[i]);       //商品i可以重复使用,重复个数在cc/W[i]和总个数N[i]中取最小值
				dp[i][cc] = dp[i - 1][cc];			   //不使用第i个商品时
				for (int k = 1; k <= count; k++){		//第i个商品使用多次,在这多次中挑一个使得总价值最大
					
					int temp = dp[i - 1][cc - k*W[i]] + k*V[i];  //放入k个商品i时的价值
					if (temp > dp[i][cc])              //找最大价值
						dp[i][cc] = temp;
				} 
			}  
		}
	}
 
	//打印观察
	for (int i = 0; i < dp.size(); i++){
		printf("使用前%d个商品:", i);
		for (int j = 0; j < dp[0].size(); j++){
			printf("%4d ", dp[i][j]);
		}
		printf("\n");
	} 
	//返回最后结果 
	return dp[n - 1][C]; 
} 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值