回溯算法-01背包问题与运动员配对问题

一、01背包问题

通过回溯算法,依次考虑每一个物品是否放入的情况

#include<iostream>
#include<fstream>
#include<vector>
#include<algorithm>
using namespace std;
/*
数据格式
(物品重量)2,5,9,10
(物品价值)4,5,6,8
*/
class Solution{
private:
	vector<int>::iterator dataItr;//指向数据首地址的迭代器
	bool* resultPtr;//指向结果的指针
	bool* tempResult;//临时结果指针
	int size;//记录背包最大重量
	int	num;//记录物件数目
	int value;//记录最大价值
public:
	Solution(vector<int>::iterator dataItr,int size,int num) {
		this->dataItr = dataItr;
		this->size = size;
		this->num = num;
		this->value = 0;
		this->tempResult = new bool[num];
		this->resultPtr = new bool[num];
		memset(this->tempResult, false, sizeof(bool) * num);
		memset(this->resultPtr, false, sizeof(bool) * num);
	}
	void backtrack(int pos,int tempValue) {
		if (pos == this->num) {//如果到头了则比较结果
			if (this->value < tempValue) {
				this->value = tempValue;
				for (int i = 0;i < this->num;i++) {
					this->resultPtr[i] = this->tempResult[i];
				}
			}
			return;
		}
        //计算负重
		this->size =  this->size - this->dataItr[pos];
		if (this->size < 0) {//如果超过了,则没有选择只能不放入
			this->size = this->size + this->dataItr[pos];//复原
			backtrack(pos + 1, tempValue);
			return;
		}
		else {
            //放入
			tempResult[pos] = true;
			tempValue = tempValue + dataItr[pos + this->num];//添加
			backtrack(pos + 1, tempValue);
			tempResult[pos] = false;
            //不放入
			this->size = this->size + this->dataItr[pos];//复原
			tempValue = tempValue - dataItr[pos + this->num];//复原
			backtrack(pos + 1, tempValue);
			return;
		}
	}
	void output() {
		cout << "最大价值为:" << this->value <<endl<<"安排为:"<< endl;
		for (int i = 0;i < num;i++) {
			if (this->resultPtr[i]) {
				cout << i << " ";
			}
		}
	}
};

int main() {
	int num = 0;//记录物件数目
	int size = 0;//记录背包最大重量
	vector<int> data;//记录数据
	ifstream ifs("data.txt", ios_base::binary);
	while (!ifs.eof()) {//记录有多少种
		int count;
		ifs >> count;//读取数据
		if (ifs.fail()) {//出问题则跳过
			ifs.clear();
			ifs.ignore(1);
			continue;
		}
		num++;
		data.push_back(count);
	}
	ifs.close();
	ifs.clear();
	num = num / 2;
	cout << "请输入背包能承受的最大重量" << endl;
	cin >> size;
	Solution solve(data.begin(), size, num);
	solve.backtrack(0,0);
	solve.output();
	return 0;
}

改进:如果在进行回溯之前先进行依照重量从小到大排序,将是否下递归用一个if句作为判断。当体积超过时,可通过返回false,省略多余的递归调用。

二、运动员最佳配对问题

#include<iostream>
#include<fstream>
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
private:
	int value;//记录最大值
	int count;//记录男女人数
	vector<vector<int>>::iterator pIter;//指向P头部
	vector<vector<int>>::iterator qIter;//指向Q头部
	vector<bool> Q;//记录Q中安排情况
public:
	Solution(vector<vector<int>>::iterator pIter, vector<vector<int>>::iterator qIter,int count) {
		this->value = 0;
		this->pIter = pIter;
		this->qIter = qIter;
		this->count = count;
		this->Q = vector<bool>(count, false);
	}
	bool backtrack(int pre,int tempValue) {
		if (pre == this->count) {
			this->value = (this->value < tempValue) ? tempValue : this->value;
			return true;
		}
		int pos = 0;
		while (pos < count) {//如果Q找完了,则结束
			if (!Q[pos]) {//如果Q未被安排
				Q[pos] = true;//安排
				tempValue += pIter[pre][pos] * qIter[pos][pre];
				if (backtrack(pre + 1, tempValue)) {//为true代表一个分支找完,不需要继续
					Q[pos] = false;//移除
					tempValue -= pIter[pre][pos] * qIter[pos][pre];
					return false;
				}
				Q[pos] = false;//移除
				tempValue -= pIter[pre][pos] * qIter[pos][pre];
			}
			pos++;
		}
		return false;
	}
	int result() { return this->value; }
};
int main() {
	int num = 0;//记录男女人数
	vector<vector<int>>P;//记录数据P
	vector<vector<int>> Q;//记录数据Q
	int count = 0;
	ifstream ifs("input.txt", ios_base::binary);
	ofstream ofs("output.txt", ios::binary);
	ifs >> num;
	P = vector<vector<int>>(num, vector<int>(num,0));
	Q = vector<vector<int>>(num, vector<int>(num, 0));
	for (int i = 0;i < 2*num;i++) {
		for (int j = 0;j < num;j++) {
			if (i < num) {
				ifs >> P[i][j];
			}
			else {
				ifs >> Q[i-num][j];
			}
			if (ifs.fail()) {//出问题则跳过
				ifs.clear();
				ifs.ignore(1);
				j--;
				continue;
			}
		}
	}
	ifs.close();
	ifs.clear();
	Solution solve(P.begin(),Q.begin(),num);
	solve.backtrack(0,0);
	ofs << solve.result();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值