1033.采药
Time Limit: 1000 MS Memory Limit: 32768 KB
Total Submission(s): 498 Accepted Submission(s): 155
Description
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?
Input
输入的第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间(1 <= t <= T)和这株草药的价值(1 <= v <= 100000)。
Output
输出包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
Sample Input
100 5
77 92
22 22
29 87
50 46
99 90
Sample Output
133
采药这个题是个背包问题,参照网上的讲解,我根据这个题了解了一下动态规划的方法
emmmm现在说一下我的理解~~
先上一下代码~
#include<stdio.h>
int tt[105]={0},v[105]={0};
int ret[1005]={0};
int max(int a,int b)
{
if(a>b)return a;
else return b;
}
int main()
{
int t,m,i,j;
scanf("%d %d",&t,&m);//t_总时间m_总数目
for(i=1;i<=m;i++)
{
scanf("%d %d",&tt[i],&v[i]);
}
for(i=1;i<=m;i++)
{
for(j=t;j>=tt[i];j--)
{
ret[j]=max(ret[j-tt[i]]+v[i],ret[j]);
}
}
printf("%d",ret[t]);
return 0;
}
代码很简单,但是这是怎么实现的呢
我是这么理解的
首先ret这个一维数组是最后的结果输出,这个规划最终会把每个时间大小的最大收益都求出来,也就是遍历考虑了所有的可能的情况,你看着是循环是顺序但是,其实是一种排列~~
首先对于第一株药~~就分成了采与不采(能采就必须得采只要时间够)————所以i=1循环后ret[100]一直到ret[77]都有了值~~采第一株药的值ret[76]--ret[1]~~~也有值只不过是0,含义是不采第一株药,原因是时间不够了
然后看第二株:前面说过只要时间够,能采则采(这样才能最优),所以j-tt[i]最大是78。这时候开始判断了(把一定时间内非最优解排除)~~对于时间为100的时候就是ret[78]+v[i]与ret[100]比发现在100内仅限两株的话还是都放最优;同理99秒也是,所以更新ret[100]与ret[99]但是在98秒的时候一二两株不能同时放了~~最优解肯定是放一不放二啊,同理ret[98]-ret[77]最优解为只放第一株,ret[76]-ret[22]最优解为只放第二株ret[1]-ret[21]最优解为0.
所以你看看到了第二株这个动态规划是不是已经把目前情况的最优解全部求得了,在进行第三株的判断的时候,就是以前两株最优解的基础上进行的
在来分析一下第三株为耗时29产值87,j=100时有了多种选择j-tt[i]=71,所以有了比较ret[100]的最优解目前是放一二株,但是来了第三株最优解会不会改变呢~~
如果放第三株,那么遗留下的时间为71,这时间只能放第二株产值为22总产值为109小于ret[100]=114;所以在三株的情况100s内最优解为放1,2不放3
同理ret[99]
到了ret[98]情况不一样了,目前ret[98]最优解为只放1,来了3后,是ret[61]+v[3]也就是放2放3与只放一比,很明显最优解为后者,通过if更新了ret[98]到ret[51](恰好能放2,3)的最优解,到了rett[50]目前其最优解为只放2,来了3,同理更新最优解为只放3,产值为87,一直这样跟新到ret[29](恰好只能放3),到了ret[28]没得选最优解只能放2,,以下不必赘述~~
这样循环完后,你会发现3株的所有最优情况又搭建好了,等待着第四株的到来
那么第四株乃至第n株就得交给计算机了~~~(相信前三株就能把这个动态规划给说明白了)