01背包问题(动态规划)

背包问题

最近刚学了01背包问题,但是听老师讲再加上以前自己看书看的,发现有很多地方很容易搞混,原理就是划分找动态转移方程,但是写程序时会遇到困难,趁着今天有空,就特意整理一下01背包问题。

动态规划的基本思想:
动态规划算法通常用于求解具有某种最优性质的问题。即我们平常所说的最优子结构性质。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法最大的区别是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的,即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。

问题描述:

给定N中物品和一个背包。物品i的重量是Wi,其价值位Vi ,背包的容量为C。问应该如何选择装入背包的物品,使得转入背包的物品的总价值为最大??

在选择物品的时候,对每种物品i只有两种选择,即装入背包或不装入背包。不能讲物品i装入多次,也不能只装入物品的一部分。因此,该问题被称为0-1背包问题。

问题分析:令V(i,j)表示在前i(1<=i<=n)个物品中能够装入容量为就j(1<=j<=C)的背包中的物品的最大价值,则可以得到如下的动态规划函数:

(1)   V(i,0)=V(0,j)=0 

(2)   (a)  V(i,j)=V(i-1,j)    j<wi  

      (b)  V(i,j)=max{V(i-1,j) ,V(i-1,j-wi)+vi) }   j>wi

(1)式表明:如果第i个物品的重量大于背包的容量,则装人前i个物品得到的最大价值和装入前i-1个物品得到的最大价是相同的,即物品i不能装入背包。
(2)式表明:如果第i个物品的重量小于背包的容量,则会有一下两种情况:(a)如果第i个物品没有装入背包,则背包中物品价值就等于把前i-1个物品装入容量为j的背包中所取得的价值。(b)如果把第i个物品装入背包,则背包物品的价值等于第i-1个物品装入容量位j-wi 的背包中的价值加上第i个物品的价值vi; 显然,取二者中价值最大的作为把前i个物品装入容量为j的背包中的最优解。

#include <iostream>
#include <algorithm>

using namespace std;

int V[200][200];//前i个物品装入容量为j的背包中获得的最大价值

int KnapSack(int n,int w[],int v[],int x[],int C)
{
    int i,j;
    for(i=0; i<=n; i++)
        V[i][0]=0;
    for(j=0; j<=C; j++)
        V[0][j]=0;
    for(i=0; i<=n-1; i++)
        for(j=0; j<=C; j++)
            if(j<w[i])
                V[i][j]=V[i-1][j];
            else
                V[i][j]=max(V[i-1][j],V[i-1][j-w[i]]+v[i]);
    j=C;
    for(i=n-1; i>=0; i--)
    {
        if(V[i][j]>V[i-1][j])
        {
            x[i]=1;
            j=j-w[i];
        }
        else
            x[i]=0;
    }
    cout << "选中的物品时:" << endl;
    for(i=0; i<n; i++)
        cout << x[i];
    cout << endl;
    return V[n-1][C];

}

int main()
{
    int s;///获得的最大价值
    int w[15];///物品的重量
    int v[15];///物品的价值
    int x[15];///物品的选取状态
    int n,i;
    int C;///背包最大容量
    cout << "请输入背包的最大容量:" << endl;
    cin >> C;

    cout << "请输入物品数:" << endl;
    cin >> n;
    cout << "请分别输入物品的重量:" << endl;
    for(i=0; i<n; i++)
        cin >> w[i];

    cout << "请分别输入物品的价值:" << endl;
    for(i=0; i<n; i++)
        cin >> v[i];

    s=KnapSack(n,w,v,x,C);

    cout << "物品价值最大为:" << endl << s << endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值