hduoj 1003 Max Sum
题目大意:
求最长连续子序列,序列的起始下标和结束下标(从1开始)。
这是一道经典DP(动态规划题目)
若想找到n个数的最大子段和,那么要找到n-1个数的最大子段和,这就出来了。
我们用 b [ i ] b[i] b[i]来表示 a [ 0 ] . . . a [ i ] a[0]...a[i] a[0]...a[i]的最大子段和, b [ i ] b[i] b[i]无非有两种情况:
(1)最大子段一直连续到 a [ i ] a[i] a[i]
(2)以 a [ i ] a[i] a[i]为首的新的子段。
由此我们可以得到 b [ i ] b[i] b[i]的状态转移方程: b [ i ] = m a x { b [ i − 1 ] + a [ i ] , a [ i ] } b[i]=max\{b[i-1]+a[i],a[i]\} b[i]=max{b[i−1]+a[i],a[i]}
最终我们得到的最大子段和为 m a x { b [ i ] , 0 < = i < n } max\{b[i], 0<=i<n\} max{b[i],0<=i<n}
#include
#include
#include
using namespace std;
const int maxn = 100010;
int a[maxn];
int n;
int l, r, temp;
int maxArray(int a[])
{
int b = 0, sum = -10000;
for (int i = 0; i < n; i++)
{
if (b >= 0)
{
b += a[i];
}
else //序列的左起点一定是之前的和小于0的时候开的一个新起点
{
b = a[i];
temp = i;
}
if (sum < b)
{
l = temp;
r = i;
sum = b;
}
}
return sum;
}
int main()
{
int T;
cin >> T;
int index = 0;
while (index < T)
{
cin >> n;
fill(a, a + n, 0);
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
int res = maxArray(a);
cout << "Case " << index + 1 << ":" << endl;
cout << res << ' ' << l + 1 << ' ' << r + 1 << endl;
if (index != T - 1)
{
cout << endl;
}
index++;
l = r = temp = 0;
}
return 0;
}
浙江大学机试题–最大连续子序列
题目大意:
给定一个整数序列,a0, a1, a2, …… , an(项可以为负数),求其中最大连续子序列和,最大连续子序列的起始元素和结束元素。如果所有整数都是负数,那么最大子序列和为0,输出原数组的起始元素和结束元素。
思路:套用求最大连续子序列和的模板。区别在于此处需要记录最大连续子序列的起始元素和结束元素。经过思考可知,最大连续子序列的起始元素一定是b < 0的时候,否则如果之前累计的和b>=0, m a x { b + a [ i ] , a [ i ] } = b + a [ i ] max\{b+a[i],a[i]\} =b+a[i] max{b+a[i],a[i]}=b+a[i]那么此时的i不可能作为最大连续子序列的起点。为什么此处的条件没有用b <=0 呢,这样不就可以把a[0]考虑进去了嘛?但是很多题目都是要求输出序号最小的left 和 right, 因此如果第一个if判断条件没有包含b=0的情况,那么就会转到else语句中,这样可能会新开一个序列了。
//1.cpp
#include
#include
using namespace std;
const int maxn = 100010;
int a[maxn];
int n;
int l, r, temp;
bool flag = false;
int maxArray(int a[])
{
int sum = -10000;
if (flag)
{
temp = a[0];
int b = 0;
for (int i = 0; i < n; i++)
{
if (b >= 0)
{
b += a[i];
}
else //序列的左起点一定是之前的和小于0的时候开的一个新起点
{
b = a[i];
temp = a[i];
}
if (sum < b)
{
l = temp;
r = a[i];
sum = b;
}
}
}
else
{
sum = 0;
l = a[0];
r = a[n-1];
}
return sum;
}
int main()
{
while (cin >> n && n != 0)
{
fill(a, a + n, 0);
for (int i = 0; i < n; i++)
{
cin >> a[i];
if (a[i] >= 0)
{
flag = true;
}
}
int res = maxArray(a);
cout << res << ' ' << l << ' ' << r << endl;
l = r = temp = 0;
flag = false;
}
return 0;
}
//2.cpp
#include
using namespace std;
const int maxn = 10001;
int a[maxn];
int dp[maxn];
int n;
bool flag = false;
int l, r,temp;
int search(int arr[])
{
int sum = -1000;
dp[0] = arr[0];
for (int idx = 1; idx < n; idx++)
{
if (dp[idx - 1] < 0)
{
dp[idx] = arr[idx];
temp = idx;
}
else
{
dp[idx] = dp[idx - 1] + arr[idx];
}
if (dp[idx] > sum)
{
l = temp;
r = idx;
sum = dp[idx];
}
}
return sum;
}
int main()
{
while (cin >> n && n != 0)
{
fill(a, a + n, 0);
for (int i = 0; i < n; i++)
{
cin >> a[i];
if (a[i] >= 0)
{
flag = true;
}
}
if (!flag)
{
cout << 0 << ' ' << a[0] << ' ' << a[n - 1] << endl;
}
else
{
int res = search(a);
cout << res << ' ' << a[l] << ' ' << a[r] << endl;
l = r = temp = 0;
}
flag = false;
}
return 0;
}
//dp[idx] = max{a[i],dp[idx-1]+a[i]};