一个背包算法的源代码

在工作中遇到一个奇怪的要求,给定空间和时间,要求将特定设备的配置最佳化,这就用到了“背包”算法,很有趣,我写了一个比较通用的算法(原理就是穷举),下面是源代码:

#include <vector>
#include <cassert>
#include <cmath>
#include <iostream>
template <typename _W, typename _V>
class Choice
{
public:
	_W weight;
	_V value;
	Choice(_W _weight, _V _value)
		: weight(_weight)
		, value(_value)
	{
	}
};
template <typename _W, typename _V>
class Item
	: public std::vector< Choice<_W, _V> >
{
};
template <typename _W, typename _V>
class ItemList
	: public std::vector< Item<_W, _V> >
{
};
class ItemChoiceIndexList
	: public std::vector<size_t>
{
};
template <typename _W, typename _V>
bool CalculateBestItemChoiceList(_W capacity,
								typename ItemList<_W, _V>::const_iterator item_begin,
								typename ItemList<_W, _V>::const_iterator item_end,
								ItemChoiceIndexList & retItemChoiceList,
								_W & retTotalWeight,
								_V & retTotalValue)
{
	assert(retItemChoiceList.empty());
	// 深度检测
	if(item_begin == item_end)
	{
		retTotalWeight = 0;
		retTotalValue = 0;
		return true;
	}
	bool findMinChoiceList = false;
	_V maxTotalValue = 0;
	for(size_t choice_i = 0; choice_i < item_begin->size(); choice_i++)
	{
		const Choice<_W, _V> & choice = (*item_begin)[choice_i];
		assert(choice.value > 0);
		// 如果当前选项大于总空间,本次组合不可选
		if(choice.weight > capacity)
		{
			continue;
		}
		// 获取剩下总空间的最佳背包组合
		ItemChoiceIndexList retRemainingItemChoiceList;
		_W retRemainingTotalWeight;
		_V retRemainingTotalValue;
		if(!CalculateBestItemChoiceList(
			capacity - choice.weight,
			item_begin + 1,
			item_end,
			retRemainingItemChoiceList,
			retRemainingTotalWeight,
			retRemainingTotalValue))
		{
			continue;
		}
		// 如果这次的组合获得的剩余空间最小,这保存这次的组合
		if(retRemainingTotalValue + choice.value > maxTotalValue)
		{
			findMinChoiceList = true;
			maxTotalValue = retRemainingTotalValue + choice.value;
			retItemChoiceList.clear();
			retItemChoiceList.push_back(choice_i);
			retItemChoiceList.insert(
				retItemChoiceList.end(), retRemainingItemChoiceList.begin(), retRemainingItemChoiceList.end());
			retTotalValue = maxTotalValue;
			retTotalWeight = retRemainingTotalWeight + choice.weight;
		}
	}
	// 没有找到合适的组合
	if(!findMinChoiceList)
	{
		return false;
	}
	assert(!retItemChoiceList.empty());
	return true;
}
int main(int argc, char ** argv)
{
	typedef unsigned int WeightType;
	typedef float ValueType;
	// 初始化ItemList用以测试
	ItemList<WeightType, ValueType> itemList;
	const int item_count = 9;
	const int choice_count = 3;
	for(int i = 0; i < item_count; i++)
	{
		Item<WeightType, ValueType> item;
		for(int w = 1; w < 2 * choice_count; w += 2)
		{
			item.push_back(Choice<WeightType, ValueType>(w, sqrt((float)w)));
		}
		itemList.push_back(item);
	}
	// 设置总空间
	const WeightType capacity = 35;
	// 测试,并获得最小剩余空间
	ItemChoiceIndexList itemChoiceList;
	WeightType totalWeight;
	ValueType totalValue;
	if(!CalculateBestItemChoiceList(
		capacity,
		itemList.begin(),
		itemList.end(),
		itemChoiceList,
		totalWeight,
		totalValue))
	{
		std::cout << "cannot calculate best item choice list" << std::endl;
	}
	else
	{
		std::cout << "the best choice list: total = "
			<< capacity << ", remaining = " << capacity - totalWeight << std::endl;
		for(size_t i = 0; i < itemList.size(); i++)
		{
			std::cout << "item [" << i << "]:";
			Item<WeightType, ValueType>::const_iterator choice_iter = itemList[i].begin();
			for(; choice_iter != itemList[i].end(); choice_iter++)
			{
				std::cout << " (" << choice_iter->weight << ", " << choice_iter->value << ")";
			}
			std::cout << " choice: " << itemChoiceList[i] + 1 << std::endl;
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值