动态规划与贪心---0-1背包与背包

本文详细介绍了0-1背包问题的解决策略,通过动态规划算法解决物品选择问题,对比了与背包问题的区别,并提供了例题演示。重点讲解了动态规划的递归关系及如何用代码实现。同时,展示了贪心算法在背包问题中的应用,通过单位价值排序进行物品选择。
摘要由CSDN通过智能技术生成

问题描述:给定n种物品和一个背包。物品i的重量是wi,其价值为vi,背包的容量为c。问:应该如何选择装入背包的物品,使得装入背包的物品总价值最大?给定的c>0,wi>0,vi>0(1<=i<=n),要求找出一个n元0-1向量(x1,x2,x3,...,xn),xi∈{0,1}(1<=i<=n)使得物品重量<=c且总价值最大。

0-1背包问题:在选择装入背包中的物品时,对每种物品i只有两种选择(装入或不装),不能将同一个物品装入多次,也不能只装入一个物品的一部分。因此,0-1背包问题为一个特殊的整数规划问题

区别于背包问题:与0-1背包不同的是,可以选择物品i的一部分,不一定要全放入。这两类问题都具有最优子结构性质。但背包问题可以用贪心算法求,而0-1背包问题不能用贪心算法求解。

对于0-1背包问题,贪心选择不能得到最优解是因为:这种情况下,不能保证背包装满,部分闲置的背包空间使每kg背包空间的价值降低了。而实际上,考虑0-1背包问题时,应该比较选择该物品和不选择该物品所导致的最终方案,再做比较。由此会导出很多相互重叠的子问题,这正是用动态规划求解的一个重要特征。

例:现有3种物品,物品1重10kg,价值60元;物品2重20kg,价值100元,物品3重30kg,价值120元。图b为0-1背包问题;图c为背包问题。

 因此0-1背包问题应该用动态规划算法(关键就在最优值的数组怎么构造,这应该要刷几百道题才能自己啥都不参考很快写出来吧)

动态规划:

1. 具有最优子结构(证明过程略)、有许多相互重叠的子问题(重叠性)

2.递归关系

关键就是用代码实现这个表达式

3. 算法描述 

例题如下:现有一背包容量为8,能装入的最大价值为多少?都装入了编号为几的物品?

 查看装了哪些物品:回溯

 以例题数据为例子,具体过程如下图: 

算法实现:

#include<iostream>
using namespace std;

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

int max(int a, int b)
{
    return a>b?a:b;
}

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;//前0个物品最大价值为0
    for (j=0;j<=C;j++)
        V[0][j]=0;//背包容量为0
    for (i=0;i<n;i++){
        for (j=0;j<=C;j++){//包容量为j的最优
            if (j<w[i])//第i个放不进去了
                V[i][j]=V[i-1][j];//最大价值=前i-1个物品时的最大价值
            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;
    }//装入的物品记为0,没装入的记为1

    cout<<"选中的物品是:"<<endl;
    for(i=0;i<n;i++)
        cout<<x[i]<<" "<<endl;
    for(int i=0;i<n;i++){
        for(int j=0;j<C+1;j++){
            cout<<V[i][j]<<" ";
            if (j==C){
                cout<<endl;
            }
        }
    }
    return V[n-1][C];//最后一个为最大价值

}

int main()
{
    int maxvalue;//获得的最大价值
    int w[4] = {2,3,4,5};//物品的重量
    int v[4] = {3,4,5,6};//物品的价值
    int x[4];//物品的选取状态
    int n=4;
    int maxvolum=8;//背包最大容量
    maxvalue=KnapSack(n, w, v, x, maxvolum);
    cout<<"最大物品价值为:";
    cout<<maxvalue<<endl;
    return 0;

}

结果:

背包问题具体的例子:

背包的容量为45kg,有5种物品,物品1重40kg,价值80¥;物品2重30kg,价值120¥;物品3重10kg,价值60¥;物品4重20kg,价值100¥;物品5重50kg,价值50¥,求该背包问题的最优解和最优值。

贪心算法要比动态规划算法容易理解的多。大致思路:计算每个物品单位价值量,按从大到小排序,依次放入,当要放入的物品重量>背包容量,则放入比例为容量/重量;否则全部放入。

算法如下:

#include <iostream>
using namespace std;

//按照单位重量的价值大到小排列
void Sort(int n,float *w,float *v)
{
    int i,j;
    float temp1,temp2;
    for(i=0;i<n;i++)
    for(j=0;j<n-i;j++)
    {
        temp1=v[j]/w[j];
        temp2=v[j+1]/w[j+1];
        if(temp1<temp2)
        {
            swap(w[j],w[j+1]);
            swap(v[j],v[j+1]);
        }
    }
}
int main()
{
    float w[5]={40,30,10,20,50};//每个物品的重量
    float v[5]={80,120,60,100,50};//每个物品的价值
    float x[5]={0};//最后放入背包的比例
    int n=5;//物品数
    float M=45;//背包最大容纳重量
    Sort(n,w,v);
    int i;
    float c=M;//更新容量
    for(i=0;i<n;i++)
    {
        if(c<w[i])
            break;//不能完全装下
        x[i]=1;
        c=c-w[i];
    }
    if(i<n)
        x[i]=c/w[i];
    for(int i=0;i<n;i++)
        cout<<"重量为"<<w[i]<<"价值量为"<<v[i]<<"的物品"<<"放入的比例为"<<x[i]<<endl;
    return 0;
}

结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值