0-1背包问题

回溯法:

#include <iostream>
#include <iomanip>
using namespace std;

int k = 0;//index 的序号
int h = 0;//向上回溯了h个节点

template <class Typew, class Typep>
class Knap
{
	friend Typep Knapsack(Typep*, Typew*, Typew, int);
	//private:
public:
	Typep Bound(int i);
	void Backtrack(int i);
	Typew c; //背包容量
	int n;   //物品数
	Typew *w;//物品重量数组
	Typep *p;//物品价值数组
	Typew cw;//当前重量
	Typep cp;//当前价值
	Typep bestp;//当前最优价值
	int *index;//满足条件的组合中物品号
};
//回溯函数
template <class Typew, class Typep>
void Knap<Typew, Typep>::Backtrack(int i) //i是当前节点
{
	
	if (i > n) //到达叶子节点
	{
		bestp = cp;
		return;
	}
	if (cw + w[i] <= c) //进入左子树
	{
		cw += w[i];
		cp += p[i];
		k++;  
	    index[k] = i;
		Backtrack(i + 1);
		
		cw -= w[i];
		cp -= p[i];
		h++;//向上回溯了h个节点
	}
	if (Bound(i + 1)> bestp) //进入右子树
	{
		if(h>0) k -= h;
		Backtrack(i + 1);
	}
}
//节点上界
template <class Typew, class Typep>
Typep Knap<Typew, Typep>::Bound(int i)
{//上界函数 
	Typew cleft = c - cw;//剩余容量
	Typep b = cp; //当前价值
	//依次装入
	while (i <= n&&w[i] <= cleft)
	{
		cleft -= w[i];
		b += p[i];
		i++;
	}
	if (i <= n)//装不下了
	{
		b += p[i] * cleft / w[i]; //物品不一定是整个的,可以只装其一部分
	}
	return b;
}

template <class Typew, class Typep>
class Object
{
	friend Typep Knapsack(Typep *, Typew *, Typew, int);
public:
	int operator <=(Object a)const
	{
		return (d >= a.d);
	}
	Object& operator =(Object a)
	{
		d = a.d;
		ID = a.ID;
		return *this;
	}
	//private:
	int ID;
	float d; //单位价值
};

//排序函数
template <class Typew, class Typep>
void Sort(Object<Typew, Typep> Q[], int n)
{
	Object<Typew, Typep> tempt;
	int flag;
	for (int i = 0; i < n; i++)
	{
		flag = i;
		for (int j = i + 1; j < n; j++)
		{
			if (Q[j].d > Q[flag].d) flag = j;
		}
		if (flag != i)
		{
			tempt = Q[i];
			Q[i] = Q[flag];
			Q[flag] = tempt;
		}
		//cout << Q[i].ID << ":" << Q[i].d << endl;
	}
}

template <class Typew, class Typep>
Typep Knapsack(Typep p[], Typew w[], Typew c, int n)
{//Backtrack的初始化
	Typew W = 0;
	Typep P = 0;
	Object<Typew, Typep> *Q = new Object<Typew, Typep>[n];
	for (int i = 1; i <= n; i++)
	{
		Q[i - 1].ID = i;
		Q[i - 1].d = 1.0*p[i] / w[i];
		P += p[i];
		W += w[i];
	}
	if (W <= c) return P; //装入所有物品
	Sort(Q, n);
	Knap<Typew, Typep> K;
	K.p = new Typep[n + 1];
	K.w = new Typew[n + 1];
	K.index = new int[n + 1];
	for (int i = 1; i <= n; i++)
	{
		K.p[i] = p[Q[i - 1].ID]; //cout<<i<<":"<<K.p[i]<<" ";
		K.w[i] = w[Q[i - 1].ID]; //cout<<i<<":"<<K.w[i]<<endl;
		K.index[i] = 0;
	}
	K.cp = 0;
	K.cw = 0;
	K.c = c;
	K.n = n;
	K.bestp = 0;

	//回溯搜索
	K.Backtrack(1);

	cout <<"可放入的物品列表:\n\n"<< "单位价值排名 " << "重量 " << "价值" << endl;
	for (int i = 1; i <= n; i++)
	{
		if (K.index[i] != 0)
			cout <<setw(8)<< K.index[i] << "      " << K.w[K.index[i]] << "   " << K.p[K.index[i]] << endl;
	}
	delete[] Q;
	delete[] K.w;
	delete[] K.p;
	//delete[] K.index; //不知道为什么,有这个delete程序就没办法返回

	return K.bestp;
}


int main()
{
	int c = 92;
	int n = 7;
	int p[8] = { 0, 55, 45, 65, 30, 40, 35, 30 };
	int w[8] = { 0, 15, 16, 15, 13, 20, 18, 14 };

	Knap<int, int> K;
	cout << "\n最多可装价值为: "<<Knapsack<int, int>(p, w, c, n)<<endl;

	return 0;
}

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值