01背包问题

01背包与贪心的区别

  • 01背包问题是考虑整体最优解
  • 贪心的前提是:局部最优解能产生全局最优解

例子:背包容量M,要求尽可能装入背包中的物品总价值最大
M: 30
重量:28 20 11
价值:28 21 11

如果用贪心算法,如果选取性价比最大的,即先选20,则后面就不可以再添加了,所以这里不能用贪心。如果物体可分割,则选取性价比策略的贪心是可以的。

描述

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。” 如果你是辰辰,你能完成这个任务吗?

input

输入的第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

output

输出包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

sample input

70 3
71 100
69 1
1 2

sample output

3

思路

想法:前i件物品中,选取若干件放入背包中
状态:在前i件物品中,选取若干件放入剩余空间为j的的背包中所获得的最大值。
决策:第i件物品放还是不放
1
w[i]和v[i]分别为第i件物品的体积和价值。
F[i-1][j]表示前i-1件物品中选取若干件放入空间为j的背包中具有的最大价值。

  • 如果F[i][j]中的i件物品选取的若干件物品中包含第i件物品,则F[i][j]=F[i-1][j-w[i]]+v[i],F[i-1][j-w[i]]为去除掉第i件的最大价值,再加上第i件的价值v[i].
  • 如果F[i][j]中的i件物品选取的若干件物品中不包含第i件物品,则F[i][j]=F[i-1][j]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    #include<stdio.h>

    int max(int a,int b)
    {

    return a>b?a:b;
    }

    struct bag
    {
    int w;//物体体积
    int v;//物体价值
    }b[105];

    int dp[105][1005];

    int main()
    {

    int T,M;
    while(scanf("%d%d",&T,&M)!=EOF)
    {
    for(int i=1;i<=M;i++)
    {
    scanf("%d%d",&b[i].w,&b[i].v);
    dp[i][0]=0;
    }
    for(int j=0;j<T;j++)
    {
    dp[0][j]=0;
    }
    for(int i=1;i<=M;i++)
    {
    //分两步
    for(int j=T;j>=b[i].w;j--)//当j大于第i个物体的体积时,即背包可以放下物体i时
    {
    dp[i][j]=max(dp[i-1][j],dp[i-1][j-b[i].w]+b[i].v);
    }
    for(int j=0;j<b[i].w;j++)//当背包放不下物体i时,则dp[i][j]只能从dp[i-1][j]转化而来
    {
    dp[i][j]=dp[i-1][j];
    }
    }
    printf("%d\n",dp[M][T]);
    }
    return 0;
    }