总结-动态规划-01背包、完全背包

前一段时间我学习了一下动态规划里面的01背包和完全背包,自己做了一些总结与大家分享一下,希望对你们有帮助
首先来说一下什么是动态规划

动态规划就是把大问题拆分成小问题,通过寻找大问题与小问题的递推关系,解决一个个小问题,最终达到解决原问题的效果。通过填写表把所有已经解决的子问题答案纪录下来,动态规划解决问题的核心就在于填表,表填写完毕,最优解也就找到。

0-1背包

问题描述:有N件物品和一个容量为V的背包。第i件物品的价值是v[i],重量是w[i]。求解将哪些物品装入背包可使价值总和最大。//具体问题:物品个数n=5,物品重量w[n+1]={0,2,2,6,5,4},物品价值V[n+1]={0,6,3,5,4,6},背包的最大容量为10,
总体思路:求K问题的最优解,就要先求出K-1问题的最优解,以此类推,最后就转化为求1问题的最优解,然后再往前推,那么K问题的最优解就求出来了。总而言之,就是把每种状态都求出来。
具体实现步骤:我画了一个表来帮助大家理解这里写图片描述

然后将每种状态都算出来,最后将表填完之后就是下面的结果。

这里写图片描述
最后数据date[ N ][ M ]就是这个问题的答案了。

代码实现如下:

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 5
#define M 10
int date[N+1][M+1],w[N+1]={0,2,2,6,5,4},v[N+1]={0,6,3,5,4,6};
void DP()
{
    for (int i=1;i<=N;i++)
    {
        for (int j=1;j<=M;j++)
        {
            if (j>=w[i])
                date[i][j]=max(date[i-1][j],date[i-1][j-w[i]]+v[i]);
            else
                date[i][j]=date[i-1][j];
            printf("%4d",date[i][j]); 
        }
        printf("\n");
    }
}
int main()
{
    memset(date,0,sizeof(date));
    DP();
    printf("%d\n",date[N][M]);
    return 0;
} 

然后就是这个代码可以进行改进,就是将存储数据的二维数组更改为一维的。关键性代码更改如下:

for (i=1;i<=N;i++)
    for (j=M;j>=1;j--)
            date[j]=max(date[j],date[j-w[i]]+v[i]);

完全背包

问题描述:有一个容积为V的背包,同时有n种物品,每种物品均有无数多个,并且每种物品的都有自己的体积和价值。求使用该背包最多能够装的物品价值总和。// 具体问题: 物品种数N=4,物品重量w[N+1]={0,2,3,4,7},物品价值V[N+1]={0,1,3,5,9},背包的最大容量为10.
总体思路:思路跟01背包差不多,分解问题,求分解问题的最优解,因为完全背包里面,每种物品是无限多的,所以每次更新数据的时候还是对这种物品进行装拿。
具体实现步骤:在这里我还是采用打表来帮助理解这里写图片描述

更新每一种状态后

这里写图片描述
最后数据date[ N ][ M ]就是这个问题的答案了。

代码实现如下:

#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
#define N 4
#define M 10
int date[N+1][M+1],w[N+1]={0,2,3,4,7},v[N+1]={0,1,3,5,9};
void DP()
{
    int i,j;
    for (i=1;i<=N;i++)
    {
        for (j=1;j<=M;j++)
        {
            if (j>=w[i])
                date[i][j]=max(date[i-1][j],date[i][j-w[i]]+v[i]);
            else
                date[i][j]=date[i-1][j];
            printf("%4d",date[i][j]);
        }
        printf("\n");
    }
}
int main()
{
    memset(date,0,sizeof(date));
    DP();
    printf("%d\n",date[N][M]);
    return 0;
}

同样的,这个代码也可以进行改进,代码更改如下:

for (i=1;i<=N;i++)
    for (j=w[i];j<=M;j++)
        date[j]=max(date[j],date[j-w[i]]+v[i]);


我这里只说明了这一种方法,如果你有其他方法,欢迎分享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值