0-1背包问题(动态规划)

来源:互联网 发布:dragonframe mac 破解 编辑:程序博客网 时间:2024/05/13 18:26
一 问题描述:
     有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
    所谓01背包,表示每一个物品只有一个,要么装入,要么不装入。

二 解决方案:
   考虑使用动态规划求解,定义一个递归式 opt[i][v] 表示前i个物品,在背包容量大小为v的情况下,最大的装载量。
     
opt[i][v] = max(opt[i-1][v] , opt[i-1][v-c[i]] + w[i]) 
   解释如下:
     opt[i-1][v] 表示第i件物品不装入背包中,而opt[i-1][v-c[i]] + w[i] 表示第i件物品装入背包中。

  花费如下:
     时间复杂度为O(V * N) ,空间复杂度为O(V * N)。时间复杂度已经无法优化,但是空间复杂度则可以进行优化。

     但必须将V 递减的方式进行遍历,即V.......0 的方式进行(其实可以V....c[i])。

knapsack:

1:只装入1个物品,确定在各种不同载重量的背包下,能够得到的最大价值      
2:装入2个物品,确定在各种不同载重量的背包下,能够得到的最大价值
。。。      
n:以此类推,装入n个物品,确定在各种不同载重量的背包下,能够得到的最大价值


printMaxValue:

确定装入背包的具体物品,从opt[n][m]向前逆推:
opt[n][m]>opt[n-1][m],则第n个物品被装入背包,且前n-1个物品被装入载重量为m-w[n]的背包中
否则,第n个物品没有装入背包,且前n-1个物品被装入载重量为m的背包中
以此类推,直到确定第一个物品是否被装入背包为止

使用二维数组opt求解:

#include<iostream>#define MAX 20#define max(a,b) a>b?a:b using namespace std;int N,V;//物品数量和容量int cost[MAX]; //费用int value[MAX];  //价值int opt[MAX][MAX];  //存放最大价值int x[MAX];//x[i]为1表示第i个物品放入背包int knapsack()//参数是物品数量和容量,X数组表示组成,F[N][V]表示最大价值{memset(opt,0,sizeof(opt));//初始化opt为0 for(int i=1;i<=N;i++)//求最大价值{for (int j=1;j<=V;j++){if (cost[i]<=j)opt[i][j]=max(value[i]+opt[i-1][j-cost[i]],opt[i-1][j]);else opt[i][j]=opt[i-1][j];}}return opt[N][V];//返回最大值}void printMaxValue()//输出opt中的值(本函数无实际作用,只是为了显示下数据){for(int i=0;i<=N;i++){for(int j=0;j<=V;j++)cout<<opt[i][j]<<" ";cout<<endl;}} void traceback()//输出放入背包的物品编号 {for(int i=N;i>0;i--)//x[i]为1表示第i个物品放入背包 {if(opt[i][V]==opt[i-1][V])x[i]=0;else{x[i]=1;V-=cost[i];}}for(int i=0;i<=N;i++)if(x[i]) cout<<i<<"  ";}int main(){while(cin>>N>>V)//输入物品数量和背包容量 {for(int i=1;i<=N;i++)cin>>cost[i]>>value[i];cout<<"max="<<knapsack2()<<endl;printMaxValue();traceback();cout<<endl;}return 0;}


优化空间复杂度为O(V),使用一维数组:

#include<iostream>#define MAX 20using namespace std;int N,V;//物品数量和容量int cost[MAX]; //费用int value[MAX];  //价值int opt[MAX];  //存放价值int knapsack()  //参数是物品数量和容量,X数组表示组成,F[N][V]表示最大价值{memset(opt,0,sizeof(opt));//初始化opt为0 for(int i=1;i<=N;i++)//求最大价值{for (int j=V;j>=cost[i];j--){if (value[i]+opt[j-cost[i]]>opt[j]) opt[j]=value[i]+opt[j-cost[i]];}}return opt[V];//返回最大值}int main(){while(cin>>N>>V)//输入物品数量和背包容量 {for(int i=1;i<=N;i++)cin>>cost[i]>>value[i];cout<<"max="<<knapsack()<<endl;}return 0;}


参考 http://www.cppblog.com/jake1036/archive/2011/06/27/149566.html


原创粉丝点击