《算法导论》练习16.2-2
0-1背包问题不能用贪心算法求解,需要使用动态规划方法。
假设窃贼可以偷的物品是Item[i](i=1...n),n为物品件数,窃贼背包可以放入的最大重量为W。
我们需要构造一个递归子过程,获取小于W的价值最多的物品。
首先选取Item[1],那么问题可以分成两部分,一部分是包括Item[1]的最优选择,一部分是
不包括Item[1]的最优选择,然后比较这两种选择,选出一个最佳者,就是我们的答案。
下面是源代码,供参考:
#include <list>
#include <vector>
#include <set>
#include <iostream>
using namespace std;
struct item
{
size_t money;
size_t weight;
};
class max_money_finder
{
public:
max_money_finder(size_t max_weight,
const vector<item>& items)
:m_max_weight(max_weight)
,m_items(items)
{
//
}
~max_money_finder()
{
//
}
size_t search(list<size_t>& item_numbers)
{
set<size_t> ignore_set;
return search_subarray(m_max_weight, ignore_set, item_numbers);
}
private:
size_t search_subarray(size_t max_weight,
const set<size_t>& ignore_set, list<size_t>& item_numbers)
{
size_t max_total_money = 0;
set<size_t> tmp_ignore_set = ignore_set;
for(size_t i=0; i<m_items.size(); ++i)
{
if(tmp_ignore_set.count(i) != 0)
{
continue;
}
if(m_items[i].weight > max_weight)
{
continue;
}
tmp_ignore_set.insert(i);
list<size_t> tmp_item_numbers;
size_t tmp_total_money = m_items[i].money
+ search_subarray(
max_weight-m_items[i].weight,
tmp_ignore_set,
tmp_item_numbers
);
if(tmp_total_money > max_total_money)
{
max_total_money = tmp_total_money;
tmp_item_numbers.push_back(i);
item_numbers.swap(tmp_item_numbers);
}
}
return max_total_money;
}
private:
size_t m_max_weight;
vector<item> m_items;
};
void print_items(size_t max_weight, const list<size_t>& item_numbers)
{
cout<<"the thief can get max weight is " << max_weight << "\n";
cout<<"item number is :\n";
list<size_t>::const_iterator citor = item_numbers.begin();
for(;citor != item_numbers.end(); ++citor)
{
cout<<(*citor)+1<< " ";
}
cout<<"\n";
}
int main()
{
vector<item> items;
//example 1
item tmp_item;
tmp_item.money = 60;
tmp_item.weight = 10;
items.push_back(tmp_item);
tmp_item.money = 100;
tmp_item.weight = 20;
items.push_back(tmp_item);
tmp_item.money = 120;
tmp_item.weight = 30;
items.push_back(tmp_item);
max_money_finder finder1(50,items);
list<size_t> item_numbers1;
size_t max_weight = finder1.search(item_numbers1);
print_items(max_weight, item_numbers1);
tmp_item.money = 110;
tmp_item.weight = 30;
items.push_back(tmp_item);
max_money_finder finder2(70,items);
list<size_t> item_numbers2;
max_weight = finder2.search(item_numbers2);
print_items(max_weight, item_numbers2);
system("pause");
}
前几天在公司做OJ练习,发现以前写的这个代码效率很低,不是真正的动态规划算法,倒是有点像穷举法,现在更新了一下代码,这个代码效率高多了:
#include <list>
#include <vector>
#include <iostream>
using namespace std;
struct item
{
size_t money;
size_t weight;
};
class max_money_finder
{
public:
max_money_finder(size_t max_weight,
const vector<item>& items)
:m_max_weight(max_weight)
,m_items(items)
{
//
}
~max_money_finder()
{
//
}
size_t search(list<size_t>& item_numbers)
{
return search_subarray(m_max_weight, 0, item_numbers);
}
private:
size_t search_subarray(size_t max_weight,
size_t index, list<size_t>& item_numbers)
{
//递归终止条件
if(index >= m_items.size())
{
return 0;
}
if(m_items[index].weight > max_weight)
{
return search_subarray(max_weight, index+1, item_numbers);
}
//计算包括下标为index的item的最优解
list<size_t> tmp_item_numbers1;
size_t tmp_total_money1 = m_items[index].money
+ search_subarray(
max_weight-m_items[index].weight,index+1,
tmp_item_numbers1);
//计算不包括下标为index的item的最优解
list<size_t> tmp_item_numbers2;
size_t tmp_total_money2 = search_subarray(
max_weight,index+1,
tmp_item_numbers2);
size_t max_total_money = 0;
if(tmp_total_money1 > tmp_total_money2)
{
max_total_money = tmp_total_money1;
tmp_item_numbers1.push_front(index);
item_numbers.swap(tmp_item_numbers1);
}
else
{
max_total_money = tmp_total_money2;
item_numbers.swap(tmp_item_numbers2);
}
return max_total_money;
}
private:
size_t m_max_weight;
vector<item> m_items;
};
void print_items(size_t max_weight, const list<size_t>& item_numbers)
{
cout<<"the thief can get max weight is " << max_weight << "\n";
cout<<"item number is :\n";
list<size_t>::const_iterator citor = item_numbers.begin();
for(;citor != item_numbers.end(); ++citor)
{
cout<<(*citor)+1<< " ";
}
cout<<"\n";
}
int main()
{
vector<item> items;
//example 1
item tmp_item;
tmp_item.money = 60;
tmp_item.weight = 10;
items.push_back(tmp_item);
tmp_item.money = 100;
tmp_item.weight = 20;
items.push_back(tmp_item);
tmp_item.money = 120;
tmp_item.weight = 30;
items.push_back(tmp_item);
max_money_finder finder1(50,items);
list<size_t> item_numbers1;
size_t max_weight = finder1.search(item_numbers1);
print_items(max_weight, item_numbers1);
tmp_item.money = 110;
tmp_item.weight = 30;
items.push_back(tmp_item);
max_money_finder finder2(70,items);
list<size_t> item_numbers2;
max_weight = finder2.search(item_numbers2);
print_items(max_weight, item_numbers2);
system("pause");
}