今天,我们来讲一讲动态规划初级篇(入门题目)。
题目如上:其题目意思是输入一行N,接下来输入N行(即测试的用例数),对于每一个测试用例输入一行,输入第一个数字我们用n表示,其后面跟的n个数字我们用数组a[]表示(我们数组从下标1开始),而对于数组,找出连续的几个数字之和最大的,并且输出最大值和该区间的左右端点下标,就如下面这个用例:5 6 -1 5 4 -7,该行有六个数字,第一个数字为5,所以后面跟5个数字,6 -1 5 4 -7。然后在这后面五个数字中,找出一个连续的区间,该区间所有值之和最大。我们可以看出,区间1-4的所有值加起来最大,值为6+(-1)+5+4=14,所以输出第一行Case 1:,第二行14 1 4。
接下来,我们主要介绍一下该动态规划的基本思路:
在此之前,我们先介绍一下这几个变量的作用。
const int mod=1e4;
a[mod]:用来表示每组数据跟在第一个数后面的数字,但在遍历的过程中,a[i]表示的是将从beg到当前位置之间所有元素的和。
left:用来记录我们答案要求的满足条件的区间左端。
right:用来标记最后满足条件的区间的右端。
maxn:用来记录遍历过程的最大值。
beg:用来更新区间左端点。(注意,这里要与left的作用区分开来,left是记录最终答案的左区间,而beg是用来寻找答案区间的左端点的位置。例如-7 3 5 -9 10,用于第一个数为负数,那么肯定不能将left置为1,即答案的区间不能从1开始,所以beg就是用来更新left的)。
lef=1; righ=1; beg=1; maxn=a[1]; for(int i=2;i<=n;i++){ if(a[i-1]>=0) a[i]=a[i]+a[i-1]; //该上一个元素大于等于0 else beg=i; //否则就将开始先设为当前位置 if(a[i]>maxn){ //如果遇到大于maxn的 maxn=a[i]; lef=beg; righ=i; } }
其实整个程序的核心就是这段代码。对数组进行遍历,先将left,right置为1,另maxn为a[1],从2开始遍历数组,如果在遍历a[i]元素之前,该区间的和已经小于0了,那么就将beg置为当前的i。否则,继续将a[i]=a[i]+a[i-1]。但是,如果遇到此时的a[i],在进行完上述步骤之后发现大于maxn,则对maxn进行更新,同时,将left也更新为当前情况下的beg,将right也置为i。直至循环结束。
#include<iostream> using namespace std; const int mod=1e5+7; int a[mod]; int n,maxn; int lef,righ,beg; int main(){ int t; cin>>t; for(int j=0;j<t;j++){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } maxn=0; lef=1; righ=1; beg=1; maxn=a[1]; for(int i=2;i<=n;i++){ if(a[i-1]>=0) a[i]=a[i]+a[i-1]; //该上一个元素大于等于0 else beg=i; //否则就将开始先设为当前位置 if(a[i]>maxn){ //如果遇到大于maxn的 maxn=a[i]; lef=beg; righ=i; } } //这些都是按题目格式输出,这不是重点,重点是上面的这个循环 cout<<"Case "<<j+1<<":"<<endl; cout<<maxn<<" "<<lef<<" "<<righ<<endl; if(j<t-1) cout<<endl; } return 0; }
如果还不理解的,请先看看我之前写的牛客博客寒假集训营2的题解C题:https://blog.nowcoder.net/n/9d821b9b4f2445749680a2777d4746cd
有疑问下方留言。