01背包问题

问题描述
  给定N个物品,每个物品有一个重量W和一个价值V.你有一个能装M重量的背包.问怎么装使得所装价值最大.每个物品只有一个.
输入格式
  输入的第一行包含两个整数n, m,分别表示物品的个数和背包能装重量。


  以后N行每行两个数Wi和Vi,表示物品的重量和价值
输出格式
  输出1行,包含一个整数,表示最大价值。
样例输入
3 5
2 3
3 5
4 7
样例输出
8
数据规模和约定

  1<=N<=200,M<=5000.



状态:
    f(i,j) 表示背包可用容量为j(1<=j<=w),已考虑物品 1,2,3, ... ,i(1<=i<=n) 时的最优解的值。
状态方程:
    f(i,j)=f(i-1,j) j<w[i]时,物品i放不下
    f(i,j)=max{f(i-1,j) , f(i-1,j-w[i])+v[i]}    j>=w[i]时,在放入和不放入物品i之间选最优解
边界条件:
    f(i,0)=0 背包不能装入任何物品,总价值为0
    f(0,j)=0 没有任何物品装入,总价值为0


方法1:

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

int main()
{
    int n,c;  //n是物品个数,c是背包容量
    cin>>n>>c;
    /*这里要注意数组申请空间是要多申请一个
    0号位赋值为0,这是为了在递推过程中f[][1]或f[1][]的值可正常推出
    */
    int *weight=new int[n+1];//重量
    int *value=new int[n+1]; //价值

    int **f=new int*[n+1];// f[i][j]表示在背包可用容量为j的情况下, 前i件宝贝的最大价值
    for(int i=0; i<=n; i++)
    {
        f[i]=new int[c+1];
    }

    for(int i=0; i<=n; i++)
        f[i][0]=0;
    for(int i=0; i<=c; i++)
        f[0][i]=0;


    for(int i=1; i<=n; i++)
    {
        cin>>weight[i]>>value[i];
    }

/*
           | 0                              i=0 or w=0
    f[i,w]=| f[i-1,w]                       wi>w
           | max(vi+f[i-1,w-wi],f[i-1,w])   i>0 and w>=wi
*/

    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=c; j++)
        {
            if(j<weight[i]) //背包装不下第i个物品,f[][]为前i-1件物品的最大价值
                f[i][j]=f[i-1][j];  
            else            //背包可以装下第i个物品,如果放比不放价值大,则放
                f[i][j]=max(f[i-1][j],f[i-1][j-weight[i]]+value[i]);  
        }
    }
    cout<<f[n][c]<<endl;
    return 0;
}
//这种方法空间利用率不高!!!


方法2:(用一维数组实现)


#include <iostream>
#include <cstring>

using namespace std;

int main()
{
    int n;//物品个数
    int c;//背包容量

    cin>>n>>c;
    int *weight=new int[n];//重量
    int *value=new int[n]; //价值

    for(int i=0; i<n; i++)
    {
        cin>>weight[i]>>value[i];
    }

    //数组多申请一个元素,容量从0~C,
    int dp[c+1];
    memset(dp,0,sizeof(dp));

    for(int i=0;i<n;i++)
    {
        for(int j=c;j>0;j--) //j为背包容量,其中容量为0时,价值势必为0,所以更新dp[]时,不用循环dp[0]
        {
            if(j>=weight[i])
                dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
        }
    }

    cout<<dp[c]<<endl;
    return 0;
}

其中代码的第24~31行可以简化,如下:

    for(int i=0; i<n; i++)
    {
        for(int j=c; j>=weight[i]; j--) //j为背包容量,其中容量为0时,价值势必为0,所以更新dp[]时,不用循环dp[0]
        {
            dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
        }
    }


posted @ 2017-11-05 23:36  詹晔晔(๑>؂<๑)  阅读(147)  评论(0编辑  收藏  举报