0-1背包问题(sort、快速排序、DFS、动态规划、回溯)

参考:0-1背包问题 —— 四种解法解题
0-1背包问题

有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?

分别用蛮力法、动态规划法、回溯法求解0/1背包问题。

输入:
3 10
5 8
8 20
4 17
输出:
1 3
25
编译:g++ -o test1 test1.cpp
执行:把数据放到 input.txt 中,就不需要每次都输数据了
Get-Content input.txt | .\test1.exe

/*******综合练习*******************
 *		用sort函数对自定义的类进行排序
 *		快速排序
 *		0-1背包问题:
 *			暴力搜索(深度优先)
 *			动态规划
 *			回溯法
 ***********************************/

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>	
using namespace std;
class goods {
public:
	int w;
	int v;
	int sign;//编号
	goods(int sign,int w, int v) {
		this->w = w;
		this->v = v;
		this->sign = sign;
	}
};
vector<goods> goo;
int N, C;//物品数量,背包容量
int bestValue, currValue, currWeigh;//最大价值,当前价值,当前重量
int X[100], currX[100];//最终存储状态,当前存储状态

bool cmpless(const goods& s1, const goods& s2);
int getstandard(vector<goods> &goo, int i, int j);
void quicksort(vector<goods> &goo, int begin, int end);//快排
void Force(int i);//暴力法
int DynamicPlan();//动态规划
void back(int i);
void BackTrack();//回溯法

int main()
{
	cin >> N >> C;//物品种类和背包容量
	for (int i = 0, w, v;i < N;i++) {
		cin >> w >> v;
		goo.push_back(goods(i+1,w, v));
	}
	/*自己试试用sort排序*/
	/*
	sort(goo.begin(), goo.end(), cmpless);
	for (int i = 0;i < N;i++) {
		cout << i << " " << goo[i].w << " " << goo[i].v << endl;;
	}*/
	/*自己试着写快排*/
	/*
	quicksort(goo, 0, N - 1);
	for (int i = 0;i < N;i++) {
		cout << goo[i].sign << " " << goo[i].w << " " << goo[i].v << endl;;
	}*/
	//Force(0);//暴力搜索,深度优先
	//bestValue = DynamicPlan();//动态规划
	BackTrack();
	for (int i = 0;i < N;i++) {
		if(X[i]==1)
			cout << i+1 << " ";
	}
	cout << endl;
	cout << bestValue << endl;
	return 0;

}

void BackTrack() {
	//回溯法
	memset(X, 0, sizeof(X));
	sort(goo.begin(), goo.end(), cmpless);//将物品按单位重量价值降序排列
	back(0);
	return;

}
void back(int i) {
	if (i > N - 1) {
		//结束条件
		//搜索到最深处,判断是否符合要求
		if (bestValue < currValue) {
			for (int k = 0;k < N;k++) {
				X[k] = currX[k];//存储更优的路径
			}
			bestValue = currValue;
		}
		return;
	}
	if (currWeigh + goo[i].w <= C) {
		//对每一步探测进行评估
		//进入左子树
		currWeigh += goo[i].w;
		currValue += goo[i].v;
		currX[i] = 1;//装入背包
		Force(i + 1);
		currWeigh -= goo[i].w;
		currValue -= goo[i].v;//回溯,进入右子树
	}
	currX[i] = 0;
	back(i + 1);
	return;
}
int DynamicPlan() {
	//动态规划
	//时间复杂度 n*C
	int V[100][10 * 100];
	for (int i = 0;i < N;i++) {
		V[i][0] = 0;
		//初始化第0列,当背包容量为0时,前j件物品能装到背包的最大价值V[j][0]=0;
	}
	for (int j = 0;j < C;j++){
		V[0][j] = 0;
		//初始化第0行,当不放物品时能装到背包中的最大价值为0;
	}
	for (int i = 1;i <= N;i++) {
		for (int j = 1;j <= C;j++) {
			/*	V(i,j)=V(i-1,j)						j<wi  *
			 *	max{V(i-1,j),V(i-1,j-wi)+vi}		j>=wi */	
			if (j < goo[i - 1].w) {
				V[i][j] = V[i - 1][j];
			}
			else {
				V[i][j] = max(V[i - 1][j], V[i - 1][j - goo[i - 1].w] + goo[i - 1].v);
			}
		}
	}
	for (int i = N, j = C;i > 0;i--) {
		if (V[i][j] > V[i - 1][j]) {
			X[i - 1] = 1;
			j = j - goo[i - 1].w;
		}
		else 
			X[i - 1] = 0;
	}
	return V[N][C];
}
void Force(int i) {
	//暴力法
	//安排第i个物品
	//递归,深度优先搜索
	//时间复杂度2^n
	if (i > N - 1) {
		//搜索到最深处,判断是否符合要求
		if (bestValue < currValue&&currWeigh <= C) {
			for (int k = 0;k < N;k++) {
				X[k] = currX[k];//存储更优的路径
			}
			bestValue = currValue;
		}
		return ;
	}
	currWeigh += goo[i].w;
	currValue += goo[i].v;
	currX[i] = 1;//装入背包
	Force(i + 1);
	currWeigh -= goo[i].w;
	currValue -= goo[i].v;
	currX[i] = 0;
	Force(i + 1);
	return;

}


bool cmpless(const goods& s1, const goods& s2) {
	return (1.0*s1.v)/s1.w > (1.0*s2.v)/s2.w;
}

int getstandard(vector<goods> &goo, int i, int j) {
	goods key = goo[i];
	while (i < j) {
		while (i < j && !cmpless(goo[j], key)) {
			j--;
		}
		if (i < j) {
			goo[i] = goo[j];
		}
		while (i < j && !cmpless(key, goo[i])) {
			i++;
		}
		if (i < j) {
			goo[j] = goo[i];
		}

	}
	goo[i] = key;
	return i;

}
void quicksort(vector<goods> &goo, int begin, int end) {
	if (begin < end) {
		int standard = getstandard(goo, begin, end);
		quicksort(goo, begin, standard - 1);
		quicksort(goo, standard + 1, end);
	}
}

猜你喜欢

转载自blog.csdn.net/MAN_Sue/article/details/107768101
今日推荐