回溯法算0-1背包

放肆的年华 提交于 2019-12-09 21:17:41
#include <stdio.h>
//#include <conio.h>
#include <fstream>
#include <iostream> 
#include <stdlib.h>
#define N 6//物品数量
#define M 3
using namespace std;
double dataArr[N*M+1];
double c;//背包容量
double v[N + 1];//各个物品的价值
double w[N + 1];//各个物品的重量
double cw = 0.0;//当前背包重量
double cp = 0.0;//当前背包中物品价值
double bestp = 0.0;//当前最优价值
int order[N + 1];
int put[N + 1];//设置是否装入
int ans[N + 1] = {0};
double perp[N + 1];
void knapsack()
{
	int i, j;
	int temporder = 0;
	double temp = 0.0;

	for (i = 1; i <= N; i++)
		perp[i] = v[i] / w[i];
	for (i = 1; i <= N - 1; i++)
	{
		for (j = i + 1; j <= N; j++)
			if (perp[i] < perp[j])
			{
				temp = perp[i];
				perp[i] = perp[j];
				perp[j] = temp;

				temporder = order[i];
				order[i] = order[j];
				order[j] = temporder;

				temp = v[i];
				v[i] = v[j];
				v[j] = temp;

				temp = w[i];
				w[i] = w[j];
				w[j] = temp;
			}
	}
}
//回溯函数
void backtrack(int i)
{
	double bound(int i);
	if (i > N)
	{

		if (cp >= bestp) //只要走过一次右子树,就满足bestp, 为了安全,强制加这个判断 
		{
			bestp = cp;

			//bestX=put[];
			for (int i=1;i<=N;i++)
			{
				ans[i]=put[order[i]];//这里很重要
				//要注意每次bestp更新时
				//我们就要把所选择的路径
				//(这里打出来是选择的路径,比如说0101这样)更新一下
				//如果在最后才输出的话,很有可能只是得到了一个中间值(甚至不是可行解)
			}
		}
		//		}
		return;
	}
	if (cw + w[i] <= c)
	{
		cw += w[i];
		cp += v[i];
		put[i] = 1;
		backtrack(i + 1);
		cw -= w[i];
		cp -= v[i];
	}

	if (bound(i + 1) >= bestp)//符合条件搜索右子数
	{
		put[i] = 0;
		backtrack(i + 1);

	}
}

//限界函数
double bound(int i)
{
	double leftw = c - cw;//剩余承重量 
	double b = cp;//当前背包价值 
	while (i <= N && w[i] <= leftw)
	{
		leftw -= w[i];
		b += v[i];
		i++;
	}
	b += v[i] / w[i] * leftw;
	return b;

}


int main()
{


	ifstream fileinput;
	fileinput.open("input.txt");
	for (int i = 0; i < N*M + 1; i++)
	{
		fileinput >> dataArr[i];
		//把txt文件中的数字全部放在data中 

	}

	c = dataArr[0];//例子中是把50赋值给C 
	//cout<<"c="<<c<<endl;
	for (int i = 1; i <= N; i++)
	{
		w[i] = dataArr[2 + M * (i - 1)]; //赋值重量到w中
		v[i] = dataArr[3 + M * (i - 1)];	//赋值价值到v中 
		order[i] = i;


	}

	knapsack();
	backtrack(1);


	cout << endl;
	cout << "最大价值为" << bestp << endl;

	for (int i = 1; i <= N; i++)
	{cout<<ans[i];	}



	cout << endl;
	cout << "背包价值排序(性价比由高到低)为" << endl;
	for (int i = 1; i <= N; i++)
	{

		printf("%d ", order[i]);

		//     cout<<put[i]<<" ";

	}
	cout << endl;
	cout << "选择的物品是:" << endl;
	for (int i = 1; i <= N; i++)
	{
		if (put[i] == 1) {
			printf("%d ", order[i]);
		}
	}

	cout << endl;
	cout << "最终路径为" << endl;
	for (int i = 1; i <= N; i++)
	{
		cout << ans[i] << " ";
	}

	return 0;
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!