由于本人水平较低,尚未接触最优算法,因此在做这题的时候自以为非常NB的用了暴力解法,结果就是一直Time Limit Exceed,然后没有办法的我只能去网上搜博客寻找思路,结果刚好找到一篇,原来这道题目是需要用dynamic programming(简称dp),即动态规划。
忽然回想起来,其实这学期也零零散散地接触了一些动态规划的问题,这个思想确实有点小难,不是很容易弄懂,我目前也只是处于门外汉的境界,目前看到过的dp问题有:背包问题,最短路径,关键路径。
其实这一类问题都是大同小异,关键是把握dp问题的核心思想,也就是如何抽象过程,将一个大过程分成一个个小过程,在小过程中达到最优效果,然后不断迭代,使得大过程也变成最优。
下面是遇到的和dp问题相关的一套题目
1361: 最大盈利
Time Limit: 1 Sec Memory Limit: 64 MB
Submit: 3406 Solved: 896
Description
徐老师前一段时间也在股市里玩了一把,而她是很细心的人,将每一天的盈亏的情况都按顺序记在本子上了,分别是a[1],a[2],…a[n]. 现在你的任务是帮她计算一下,从哪一天到哪一天这段时间里她的盈利是最多的。比如,(6,-1,5,4,-7), 她盈利最多的是6 + (-1) + 5 + 4 = 14.
Input
第一行输入一个整数T, 表示她有T本账本(最多不超过20),对于每一本账本,都有一行数据。每行数据第一个数字是一个整数N ( 1 <= N <= 100000 ), 然后是N个整数(-500到500之间)。
Output
对于每本账本,你要输出2行,第一行是:“Payoff #:”, #是账本号. 第2行包含三个数,最大盈利、该最大盈利起始编号与终止编号。如果有很多这样的结果,只输出第一个出现的最大盈利的情况。在2个账本之间要输出一个空行。
Sample Input
2
5 6 -1 5 4 -7
7 0 6 -1 1 -6 7 -5
Sample Output
Payoff 1:
14 1 4
Payoff 2:
7 1 6
暴力解法代码如下:
#include<stdio.h>
#include<math.h>
int main()
{
int n;
scanf("%d",&n);
int p=1;
while(n--)
{
int x;
scanf("%d",&x);
int i;
int a[x+1];
for(i=1;i<=x;i++)
{
scanf("%d",&a[i]);
}
int begin=1,end=1,j;
int max=a[1];
for(i=1;i<=x;i++)
{
int sum=0;
if(a[i]>=0)
{
for(j=i;j<=x;j++)
{
sum=sum+a[j];
if(sum>max)
{
max=sum;
begin=i;
end=j;
}
}
}
}
printf("Payoff %d:\n",p) ;
printf("%d %d %d\n",max,begin,end);
p++;
putchar('\n');
}
}
思路非常简单,就是穷尽所有情况,然后找出最大值(注释我就不写了。)
但是当数据非常多的时候,这个方法是非常慢的,效率很低。
很多人都说程序员和码农是俩个生物,确实是这样,其实学习到了后期,实现功能这一块都是比较基础的,主要是看你编写的程序效率高不高,运行快不快,稳不稳定。而码农就是直接莽,暴力解下去,自以为写了很多代码,感觉自己很牛逼,其实麻烦的要死。(对,就是我。。)而程序员就是很会“偷懒”,用最简洁的代码,最佳的算法来编写程序。
好了,说了一些题外话。
下面是优化后的算法
#include<stdio.h>
#include<math.h>
int main()
{
int n;
scanf("%d",&n);
int p=1;
while(n--)
{
int x;
scanf("%d",&x);
int i;
int a[x+1];
for(i=1;i<=x;i++)
{
scanf("%d",&a[i]);
}
int begin1=1,begin2=1,end=1,j;
int max=a[1],sum=a[1];
for(i=2;i<=x;i++)
{
if(sum+a[i]>=a[i]) //加上目标
{
sum=sum+a[i];
}
else //放弃前面,加上目标
{
sum=a[i];
begin2=i;
}
if(sum>max) //选择每次确定的最大值中的最大值
{
max=sum;
end=i;
begin1=begin2;
}
}
printf("Payoff %d:\n",p) ;
printf("%d %d %d\n",max,begin1,end);
p++;
putchar('\n');
}
}
这里面最难理解的地方就是这句“选择每次确定的最大值中的最大值”,因为你每次确定一个最大值,实际上是局部的最大值,而你要的是全局的最大值,因此才会在每次确定一个局部最大值sum后,再和全局最大值max进行比较,让max等于更大的那个值。
如果觉得有帮助,可以关注一下我的公众号,我的公众号主要是将这些文章进行美化加工,以更加精美的方式展现出来,同时记录我大学四年的生活,谢谢你们!