C++回溯法和动态规划求解0-1背包问题

题目:

0-1背包问题:给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?在选择装入背包的物品时,对每种物品i只有2种选择,即装入背包或不装入背包。不能将物品i装入背包多次,也不能只装入部分的物品i。请分别用动态规划和回溯法编程求解该问题。

两个测试用例:输入数据分别由文件名为 input1.txt、input2.txt的文本文件提供,文件的第1行有2个正整数n和C,分别表示物品数和背包的容量,第2行有n个正整数,表示物品的价值,第3行有n个正整数,表示物品的重量。请分别计算并给出装入背包中物品的最大价值。

这边我用了文件,大家自己创建个文本并修改下地址即可、

样例2:

50 1000
2 4 10 65 10 1 60 25 4 15 50 10 50 45 60 30 85 55 50 25 30 72 66 40 20 82 48 30 70 38 70 80 35 55 30 32 50 40 20 32 28 50 20 30 32 22 25 22 10 25
1 3 8 65 10 1 70 30 5 20 69 15 80 75 110 58 198 130 120 60 73 180 165 100 50 208 122 77 180 100 192 220 98 160 88 96 155 125 63 101 90 162 66 105 118 82 95 115 56 158

//动态规划
#include<bits/stdc++.h>
using namespace std;
int n, C;
int value[200];
int weight[200];

int OptimalSolution[200];       //最优解;OptimalSolution[i]=1代表物品i放入背包,0代表不放入
int judge[200]; //物品i放入背包,0代表不放入
int Sumvalue = 0;
int Sumweight = 0;
int OptimalValue = 0;  //最优价值;当前的最大价值,初始化为0


int main() {
	fstream fp;
	fp.open("C://Users//Administrator//Desktop//算法//实验5:0-1背包问题//0-1背包问题 input 1.txt", ios::in);
	if (!fp.is_open()) {
		cout << "打开文件失败!!\n";
		return 1;       // 返回异常;
	}

	fp >> n >> C;
	
	for (int i = 0; i < n; i++) {
		fp >> value[i];
	}

	
	for (int i = 0; i < n; i++) {
		fp >> weight[i];
	}
	//动态规划
	int dp[80][1100] = { 0 };
	for (int j =weight[0]; j <= C; j++) {
		dp[0][j] = value[0];//第一行大于背包容量大于物品质量的放物品0的价值
	}
	for (int i = 1; i < n; i++) {// 遍历物品 因为第一行已经放过,所以从第二行就是第二个物品开始放
		for (int j = 0; j <=C; j++) {// 遍历背包容量
			if (j < weight[i]) {
				dp[i][j] = dp[i - 1][j];
			}
			else {
				dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
			}
		}
	}
	cout << dp[n-1][C]<<endl;
	
}
//回溯法
#include<bits/stdc++.h>
using namespace std;
int n, C;
int value[200];
int weight[200];

int OptimalSolution[200] = {0};       //最优解;OptimalSolution[i]=1代表物品i放入背包,0代表不放入
int judge[200] = {0}; //物品i放入背包,0代表不放入
double Sumvalue = 0;
int Sumweight = 0;
int OptimalValue = 0;  //最优价值;当前的最大价值,初始化为0

bool critize(int t, int Sweight, int Svalue) {
	int temp = Svalue;
	while (t <= n && C - Sweight >= weight[t]) {
		Sweight += weight[t];
		temp += value[t];
		t++;
	}
	if (t <= n)temp += value[t] * 1.0 / weight[t] * (C - Sweight);
	if (temp > OptimalValue)return true;
	else return false;
}

void backtrck(int t, int Sumweight, int Sumvalue) {
	if (t > n) {
		if (Sumvalue > OptimalValue) {
			OptimalValue = Sumvalue;
			//cout << "#$%^" << Sumvalue;
			for (int i = 1; i <= n; i++) {
				OptimalSolution[i] = judge[i];
			}
		}

	}
	else {
		//遍历当前节点的子节点:0 不放入背包,1放入背包
		
		if (C - Sumweight >= weight[t]) {
			Sumweight += weight[t];
			Sumvalue += value[t];
			judge[t] = 1;//标记已经放入	
			backtrck(t + 1, Sumweight, Sumvalue);
			judge[t] = 0;
			Sumweight -= weight[t];
			Sumvalue -= value[t];
		}
		if(Sumweight<=C && critize(t,Sumweight,Sumvalue))backtrck(t + 1, Sumweight, Sumvalue);

	}
}

int main() {
	fstream fp;
	fp.open("C://Users//Administrator//Desktop//算法//实验5:0-1背包问题//0-1背包问题 input 2.txt", ios::in);
	if (!fp.is_open()) {
		cout << "打开文件失败!!\n";
		return 1;       // 返回异常;
	}

	fp >> n >> C;

	for (int i = 1; i <= n; i++) {
		fp >> value[i];
	}


	for (int i = 1; i <= n; i++) {
		fp >> weight[i];
	}
	
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			double a = (double)value[i] / weight[i];
			double b = (double)value[j] / weight[j];
			if (a > b) {
				swap(weight[i], weight[j]);
				swap(value[i], value[j]);
			}
		}
	}
	int t = 1;
	
	backtrck(t, Sumweight, Sumvalue);
	cout << OptimalValue << endl;

	
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
0-1背包问题是一个经典的动态规划问题,也可以用回溯求解,以下是C++的实现代码: ``` #include <iostream> #include <vector> using namespace std; // 递归回溯求解0-1背包问题 void backtrack(vector<vector<int>>& res, vector<int>& items, vector<int>& selected, int capacity, int start) { if(capacity < 0) { return; } if(start == items.size() || capacity == 0) { res.push_back(selected); return; } // 不选当前物品 backtrack(res, items, selected, capacity, start + 1); // 选当前物品 selected[start] = 1; backtrack(res, items, selected, capacity - items[start], start + 1); selected[start] = 0; } vector<vector<int>> solveKnapsack(vector<int>& items, int capacity) { vector<vector<int>> res; vector<int> selected(items.size(), 0); backtrack(res, items, selected, capacity, 0); return res; } int main() { vector<int> items = {2, 3, 4, 5}; int capacity = 7; vector<vector<int>> res = solveKnapsack(items, capacity); for(int i = 0; i < res.size(); i++) { for(int j = 0; j < res[i].size(); j++) { if(res[i][j] == 1) { cout << items[j] << " "; } } cout << endl; } return 0; } ``` 代码思路: 1. 递归函数 backtrack 用于求解 0-1 背包问题,参数 res 表示最终结果,items 表示所有物品的重量,selected 表示当前选中的物品,capacity 表示当前背包的容量,start 表示当前处理的物品编号。 2. 如果当前背包已经装满了或者已经处理完了所有物品,则将结果加入到 res 中,否则分别尝试选取当前物品和不选取当前物品两种情况。 3. 主函数中调用 solveKnapsack 函数求解 0-1 背包问题,并输出结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值