浅谈C——动态规划之采药问题

第一次写博客,也没什么好分享的,(其实自己也不怎么会)

好了,不多BB了,入正题。

采药

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

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

输入

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

输出

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

样例输入

70
3

71 100

69 1

1 2

样例输出

3

备注:
`这个题目,其实就是0-1背包问题,而对于动态规划,最重要的是要确定好状态

所谓状态,就是与题目有关的几个变量的组合,确定好后,代码就很好写了。

要注意的一点是:动态规划中,经常能碰到可以优化空间的问题,而此题恰好可以
我们在求解动态规划的问题时,你的思想可以是一个递归型的,即,你先做一步,之后再看看你下一步该做什么。
动态递归虽好,可以解决很多最优解问题,但问题本身需要满足两个条件。
1.最优子结构性质。//即子问题中也要保证是可以最优化的。
2.无后效性//状态的确定,它不取决于是怎么确定的,状态一旦确定,后续问题求解就紧紧围绕在这些个状态之间。


#include "iostream"
#include<cmath>
using namespace std;
int w[105],val[105];//对于每株草药,都是采与不采两个选择
int dp[105][1005];//所以我们可以确定状态为 采前i株草药所能到达的最大价值
int main()        //当我们分别求出了前1株,前2株,前3株,前4株......的最大价值,这些值中取个最大值不就是了吗?
 //

{
  int t,m,scanf("%d%d",&t,&m);

for(int i=1;i<=m;i++)
{
scanf("%d%d",&w[i],&val[i]);//输入
}

for(int i=1;i<=m;i++) 
for(int j=t;j>=0;j--) {

if(j>=w[i])//要能采,首先保证时间够用!!
{//第i株,采与不采,两种情况中取个最大值,不采,那个就是在i-1株中操作,即dp[i-1][j] ,采了,花去了时间w[i],但得到了价值val[i],       //即dp[i-1][j-w[i]]+val[i];

 dp[i][j]=max(dp[i-1][j-w[i]]+val[i],dp[i-1][j]);//状态转移方程,
}  
else           
{
                dp[i][j]=dp[i-1][j];//时间不够,这株采不了,就只能是前i-1株了。
}                   
}   
printf("%d",dp[m][t]);   
return 0;
}

刚刚说了,这是用二维数组存放的值,一旦数据范围大起来,便会***超内存***,我们可以从状态转移方程来分析

要得到dp[i][j],那么我们就要知晓 上一行的元素值

dp[i][j]=max(dp[i-1][j-w[i]]+val[i],dp[i-1][j])

也就是说,每次我们都只是在上下两行操作,

这是不是就意味着,我们每次求出当前的一行,那上一行的值是不是就没用了?

所以,我们便可用一维数组来保存数值,每次求出数值后,直接覆盖在原来的位置,此外还要注意遍历的方向要与方程符合。

上代码:


#include<iostrean>
#include<cmath>
using namespace std;
int w[105], val[105];
int dp[1005];
int main()
{   
int t,m,res=-1;       
scanf("%d%d",&t,&m);  
for(int i=1;i<=m;i++)
{     
scanf("%d%d",&w[i],&val[i]);
}   
for(int i=1;i<=m;i++){       
for(int j=t;j>=0;j--){           
if(j>=w[i])          
{
    dp[j]=max(dp[j-w[i]]+val[i],dp[j]);           
}       
}   
}       
printf("%d",dp[t]);   
return 0;
}

这样虽然效率没变,但空间上大大优化了!

总之,还是要多多理解,动态规划没有一个固定的思维和套路,顶多步骤一般都是先想好状态,再分析写出递推或递归。

所以,还是要多加练习!

好了,就这么多了,(o)/~。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值