动态规划--最长连续子序列

最长连续子序列

题一

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[i1]+a[i],a[i]}

最终我们得到的最大子段和为 m a x { b [ i ] , 0 &lt; = i &lt; n } max\{b[i], 0&lt;=i&lt;n\} max{b[i],0<=i<n}

#include <iostream>
#include <algorithm>
#include <vector>
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;
}
  • 最后要清空一下l,r,temp!!!WA了好久这里…

题二

浙江大学机试题–最大连续子序列

题目大意:

给定一个整数序列,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 <iostream>
#include <algorithm>
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 <iostream>
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]};
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值