0-1背包问题

《算法导论》练习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");
}

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值