题目
Description
给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ...,
Nj },其中 1 <= i <= j <= K。最大连续子序列是所有连续子序列中元素和最大的一个,
例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{ 11, -4, 13 },最大和
为20。
在今年的数据结构考卷中,要求编写程序得到最大和,现在增加一个要求,即还需要输出该
子序列的第一个和最后一个元素。Input
测试输入包含若干测试用例,每个测试用例占2行,第1行给出正整数K( < 10000 ),第2行给出K个整数,中间用空格分隔。当K为0时,输入结束,该用例不被处理。
Output
对每个测试用例,在1行里输出最大和、最大连续子序列的第一个和最后一个元
素,中间用空格分隔。如果最大连续子序列不唯一,则输出序号i和j最小的那个(如输入样例的第2、3组)。若所有K个元素都是负数,则定义其最大和为0,输出整个序列的首尾元素。Sample Input
6
-2 11 -4 13 -5 -2
10
-10 1 2 3 4 -5 -23 3 7 -21
6
5 -8 3 2 5 0
1
10
3
-1 -5 -2
3
-1 0 -2
0Sample Output
20 11 13
10 1 4
10 3 5
10 10 10
0 -1 -2
0 0 0
题解
曾经做过>类似的题目<
两种思路:
- 动态规划(这个专题要求的)
- 递归与分治(类似的题目使用的方法)
先测试之前的代码,可以AC
换用动态规划
思路是:对于某一个值,可以选择将它加入到子序列里,或者选择从它开始一个新的子序列
也即**dp[i] = max(dp[i-1]+a[i] , a[i])
**
然后查找dp
中最大的值即可
其实我觉得处理起始和末尾才是最难的
末尾就是找到dp中最大值对应的下标指向的序列中的数字
起始需要从末尾开始往前倒推
代码
动态规划
/* By:OhYee Github:OhYee Blog:http://www.oyohyee.com/ Email:oyohyee@oyohyee.com かしこいかわいい? エリーチカ! 要写出来Хорошо的代码哦~ */ #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <vector> #include <list> #include <queue> #include <stack> #include <map> #include <set> #include <functional> using namespace std; const int INF = 0x7FFFFFFF; const int maxn = 10005; int dp[maxn]; int a[maxn]; bool Do() { int n; scanf("%d",&n); if(n == 0) return false; memset(dp,0,sizeof(dp)); for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); dp[i] = max(dp[i - 1] + a[i],a[i]); } int begin,end = a[1],Max = dp[1],pos=1; for(int i = 1;i <= n;i++) { if(dp[i] > Max) { Max = dp[i]; end = a[i]; pos = i; } } int sum = 0; begin = a[pos]; for(int i = pos;i > 0;i--) { if(Max > sum) { sum += a[i]; begin = a[i]; } else { break; } } if(Max >= 0) printf("%d %d %d\n",Max,begin,end); else printf("%d %d %d\n",0,a[1],a[n]); return true; } int main() { while(Do()); return 0; }
递归与分治
/* By:OhYee Github:OhYee Blog:http://www.oyohyee.com/ Email:oyohyee@oyohyee.com かしこいかわいい? エリーチカ! 要写出来Хорошо的代码哦~ */ #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <vector> #include <list> #include <queue> #include <stack> #include <map> #include <set> #include <functional> using namespace std; const int maxn = 100005; //const int INF = (1 << 31) - 1; const int INF = 0x7fffffff; int a[maxn]; int dfs(int *a,int l,int r,int &begin,int &end) { if(l == r) { begin = end = l; return a[l]; } if(l > r) { begin = end = -1; return -INF; } int mid = (l + r) / 2; int Max; int ans; int tbegin,tend; begin = end = mid; //中间 int i; ans = 0; int maxl = 0; for(i = mid - 1;i >= l;i--) { ans += a[i]; if(ans >= maxl) { maxl = ans; begin = i; } } ans = 0; int maxr = 0; for(i = mid + 1;i <= r;i++) { ans += a[i]; if(ans > maxr) { maxr = ans; end = i; } } Max = maxl + a[mid] + maxr; //左侧 ans = dfs(a,l,mid - 1,tbegin,tend); if(ans >= Max) { Max = ans; begin = tbegin; end = tend; } //右侧 ans = dfs(a,mid + 1,r,tbegin,tend); if(ans > Max) { Max = ans; begin = tbegin; end = tend; } return Max; } bool Do() { int n,l,r; scanf("%d",&n); if(n== 0) return false; for(int i = 1;i <= n;i++) scanf("%d",&a[i]); int ans = dfs(a,1,n,l,r); if(ans >= 0) printf("%d %d %d\n",ans,a[l],a[r]); else printf("%d %d %d\n",0,a[1],a[n]); return true; } int main() { while(Do()); return 0; }