第一次写博客,也没什么好分享的,(其实自己也不怎么会),
好了,不多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)/~。