您的位置:首页 > 其它

动态规划求解0/1背包问题

2011-08-23 18:08 381 查看
什么是动态规划?

动态规划是一种在数学和计算机科学中使用的,用于求解包含重叠子问题的最优化问题的方法。其基本思想是,将原问题分解为相似的子问题,在求解的过程中通过子问题的解求出原问题的解。动态规划的思想是多种算法的基础,被广泛应用于计算机科学和工程领域。比较著名的应用实例有:求解最短路径问题,背包问题,项目管理,网络流优化等。

动态规划在查找有很多重叠子问题的情况的最优解时有效。它将问题重新组合成子问题。为了避免多次解决这些子问题,它们的结果都逐渐被计算并被保存,从简单的问题直到整个问题都被解决。因此,动态规划保存递归时的结果,因而不会在解决同样的问题时花费时间。

动态规划只能应用于有最优子结构的问题。最优子结构的意思是局部最优解能决定全局最优解(对有些问题这个要求并不能完全满足,故有时需要引入一定的近似)。简单地说,问题能够分解成子问题来解决。

实施动态规划的步骤:

最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。

子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。

什么是0/1背包问题?

我们有n种物品,物品j的重量为wj,价格为pj。我们假定所有物品的重量和价格都是非负的。背包所能承受的最大重量为W

如果限定每种物品只能选择0个或1个,则问题称为0-1背包问题。可以用公式表示为:

  maximize


  subject to


问题求解:

我们将在总重量不超过Y的前提下,前j种物品的总价格所能达到的最高值定义为A(j, Y)。

A(j, Y)的递推关系为:

A(0, Y) = 0

A(j, 0) = 0

如果wj > Y, A(j, Y) = A(j - 1, Y)

如果wjY, A(j, Y) = max { A(j - 1, Y), pj + A(j - 1, Y - wj) }

通过计算A(n, W)即得到最终结果。为提高算法性能,我们把先前计算的结果存入表中。

  下面给出代码:

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

struct Item
{
void SetItem(int w, int v, bool s)
{
weight = w;
value = v;
selected = s;
}
int weight;
int value;
bool selected;
};

int Pick(Item goods[],int totalWeight,int amount)
{
int c[amount + 1][totalWeight + 1];

for(int i = 0; i < amount + 1; ++i)
c[i][0] = 0;
for(int j = 0; j < totalWeight + 1; ++j)
c[0][j] = 0;

for(int i = 1; i < amount + 1; ++i)
for(int j = 1; j < totalWeight + 1; ++j)
{
if(goods[i].weight < j + 1)
c[i][j] = max(c[i - 1][j], c[i - 1][j - goods[i].weight] + goods[i].value);
else
c[i][j] = c[i - 1][j];
}

for(int i = 0; i < amount + 1; ++i)
{
for(int j = 0; j < totalWeight + 1; ++j)
{
cout<<"\t"<<c[i][j]<<" ";
}
cout<<endl;
}

for(int i = amount, j = totalWeight; i > 0; --i)
{
if(c[i][j] > c[i - 1][j])
{
goods[i].selected = true;
j = j - goods[i].weight;
}
}

return c[amount][totalWeight];

}

int main()
{
int amount = 5;
int totalWeight = 10;
Item * goods = new Item[amount + 1];
goods[0].SetItem(0, 0, false);
goods[1].SetItem(2, 6, false);
goods[2].SetItem(2, 3, false);
goods[3].SetItem(6, 5, false);
goods[4].SetItem(5, 4, false);
goods[5].SetItem(4, 6, false);

int value = Pick(goods, totalWeight, amount);

cout<<"Max value is "<<value<<endl;
cout<<"Good picked are :"<<endl;;
for(int i = 0; i < amount + 1; ++i)
{
if(goods[i].selected)
cout<<"index = "<<i<<" -> "<<"weight = "<<goods[i].weight<<" "<<"value = "<<goods[i].value<<endl;;
}

delete [] goods;
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: