动态规划 入门

「动态规划」01背包问题

我是一名初学计算机得菜鸟,这也是我第一次写博客,但这也会让我去查阅更多的资料并且更认真的面对这次。

该问题的基本模板:有n个物品,他们有各自的体积和价值,现有一定容量的背包,如何使该背包装入的物品的价值和最大

物品序号1234
体积5678
价值56810

以上我们任意的给了一些数值,为了方便读者的理解。

首先我们先提一下解决动态规划问题的过程

1.定义数组的含义:什么是定义数组的含义呢?我举几个简单的例子:比如你可以用f[2] [2]来储存前三个物品在体积为二的背包中能装的最大价值。

2.找数组之间的关系:这点也是动态规划的最重要一点,也就是所谓的动态转移方程。

3.找方程退出的初始值。

下来我们直接来进入一些题目来进行讲解

题目描述

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

如果你是辰辰,你能完成这个任务吗?

输入格式

第一行有 2 个整数 T(1≤T≤1000)和 M(1≤M≤100),用一个空格隔开,T 代表总共能够用来采药的时间,M 代表山洞里的草药的数目。

接下来的 M 行每行包括两个在 1 到 100 之间(包括 1 和 100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式

输出在规定的时间内可以采到的草药的最大总价值。

输入输出样例

输入 #1

70 3
71 100
69 1
1 2

输出 #1

3
# include <stdio.h>

int main(void){
    int m,t;//这里的t就表示的是背包的体积
    scanf("%d %d",&t,&m);//对初始两变量的赋值
    int a[m];//表示所消耗的时间
    int b[m];//所有的价值
    int i;
    for(i = 0;i < m;++i){
        scanf("%d %d",&a[i],&b[i]);
    }
    int dp[m][t+1];//该数组的含义背包问题上面开始所提到的含义
    int j;
    for(i = 0;i <= t;++i){//这里dp的出口
        dp[0][i] = 0;
        if(i >= a[0])
            dp[0][i] = b[0];
    }
    for(i = 1;i < m;++i){
        for(j = 0;j <= t;++j){
            dp[i][j] = dp[i - 1][j];//我们总是先定义当前的总是不选第i个的
            if(j >= a[i]){
                dp[i][j] = dp[i][j] > (dp[i - 1][j - a[i]] + b[i])?dp[i][j] : (dp[i - 1][j - a[i]] + b[i]);//这里就是状态转移方程,从选和不选中找出最大的
            }
        }
    }
    printf("%d",dp[m - 1][t]);//这里输出最后一个便是 t体积下的最大价值
    return 0;
}

好,这段代码我们就写完了,先来我们在来写一种这段代码的优化

# include <stdio.h>
# define N 1001
int dp[N];
int main(void){
    int t,m;//与上面一样
    scanf("%d %d",&t,&m);
    int w[m],v[m];
    int i;
    for(i = 0;i < m;++i){
        scanf("%d %d",&w[i],&v[i]);
    }
    int j;
    for(i = 0;i < m;++i){
        for(j = t;j >= w[i];j--){//想一想这里为什么反着赋值 tip:该背包的物品都只有一件哦!
            dp[j] = dp[j] > dp[j - w[i]] + v[i]?dp[j]:dp[j - w[i]] + v[i];
            //遇到问题想一想问什么要定义整体变量而不是局部变量
            //想一下这个是如何跳出dp的
        }
    }
    printf("%d",dp[t]);
    return 0;
}

这次的分享就此结束

下面我还会写 完全背包问题 和 多重背包问题 感兴趣的可以去我的博客查看哦!

如果有描述不得当的地方希望能够指出。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值