算法设计--0-1背包问题

算法设计--0-1背包问题通过动态规划

  给定一个物品集合s={1,2,3,…,n},物品i的重量是wi,其价值是vi,背包的容量为W,即最大载重量不超过W。在限定的总重量W内,我们如何选择物品,才能使得物品的总价值最大。

  如果物品不能被分割,即物品i要么整个地选取,要么不选取;

  不能将物品i装入背包多次,也不能只装入部分物品i,则该问题称为0—1背包问题。

  如果物品可以拆分,则问题称为背包问题,适合使用贪心算法。

  假设xi表示物品i装入背包的情况,xi=0,1。

  当xi=0时,表示物品没有装入背包; 当xi=1时,表示把物品装入背包。

  因此问题就归结为找到一个满足上述约束方程, 并使目标函数达到最大的解向量。

  

  p(i,j):背包容量j。   p(i+1,j):不装入物体i,背包容量j。  p(i+1,j-wi)+vi:装入物体i,背包容量j-wi。

#include<bits/stdc++.h>
using namespace std;
#define NUM 50//物品数量的上限
#define CAP 1500//背包容量的上限
int w[NUM];//物品的重量
int v[NUM];//物品的价值
int p[NUM][CAP];//用于递归的数组
void knapsack(int c,int n)//c是背包的容量,n是物品的数量
{//计算推理边界
    int jMax=min(w[n]-1,c);//分界点
    for( int j=0; j<=jMax; j++)   p[n][j]=0;
    for(int j=w[n];j<=c;j++)p[n][j]=v[n];
    for(int i=n-1;i>1;i--)//计算递推式
    {
        jMax=min(w[i]-1,c);
        for(int j=0;j<=jMax;j++)
        p[i][j]=p[i+1][j];
        for(int j=w[i];j<=c;j++)
        p[i][j]=max(p[i+1][j],p[i+1][j-w[i]]+v[i]);
    }
    p[1][c]=p[2][c];//计算最优值
    if(c>=w[1])p[1][c]=max(p[1][c],p[2][c-w[1]]+v[1]);
}
void traceback(int c,int n,int x[])
{
    for(int i=0;i<n;i++)
    {
        if(p[i][c]==p[i+1][c])x[i]=0;
        else{
            x[i]=1;c-=w[i];
        }
    }
    x[n]=(p[n][c])?1:0;
    for(int i=0;i<n;i++)
    {
        cout<<x[i];//逆向推导
    }
}
int main()
{
    for(int i=0;i<4;i++)
    {
        cin>>w[i];//2 1 3 2 12 10 20 15
    }
    for(int i=0;i<4;i++)
    {
        cin>>v[i];
    }
    int x[4];
    knapsack(5,4);
    traceback(5,4,x);
}

猜你喜欢

转载自blog.csdn.net/qq_43238335/article/details/105307767
今日推荐