POJ 2479 动态规划

题意:给出若干个数,要求计算一个公式,公式是这些数排成一列后把他分成不相交的两部分(中间和两侧可以有若干个数不取),求出满足这样要求的一种分割方式,使得在这种分割方式下,被选入的数的和最大。


思路:在数列中任取一点i,求出这点左边的数的最大子序列和dp2[i],再求出这点右边的最大子序列和dp1[i],最后枚举分段点取所有dp2[i-1]+dp1[i]中的最大值就是答案。


而dp2和dp1的计算方法是:先求出以任意一点为终点的最长子序列left[i](还有以任意一点为起点的最长子序列right[i])然后dp2[i]就是i点左边的最大的left[i](dp1[i]就是i点右边最大的right[i])


下面是代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <ctype.h>
#include <cstring>
#include <string>
#include <queue>
#include <cmath>

#define MAXN 50010
#define INF 2100000000
#define pu system("PAUSE")

#pragma comment(linker, "/STACK:16777216");

using namespace std;

int n;
int a[MAXN];
int dp1[MAXN];
int dp2[MAXN];
int main()
{
    //freopen("C:/Users/Admin/Desktop/in.txt", "r", stdin);
    int t;
    cin >> t;
    while(t--)
    {
        memset(dp2, 0, sizeof(dp2));
        memset(dp1, 0, sizeof(dp1));
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
        {
            scanf("%d", &a[i]);
        }

        int ans, ans1, ans2;


        //先算右半截
        dp1[n-1] = a[n-1];
        for(int j = n-1; j >= 0; j--)
        {
            dp1[j] = max(dp1[j+1]+a[j], a[j]);
            //ans1 = max(ans1, dp1[j]);
        }

        //再算左半截
        dp2[0] = a[0];
        for(int j = 1; j < n; j++)
        {
            dp2[j] = max(a[j], dp2[j-1]+a[j]);
            //ans2 = max(ans2, dp2[j]);
        }

        //for(int i = 1; i < n-1; i++) dp2[i] = max(dp2[i], dp2[i-1]);
        for(int i = n-2; i >= 0; i--) dp1[i] = max(dp1[i], dp1[i+1]);//前面i=n-1越界了WA到哭。。。



        ans = dp2[0] + dp1[1];
        for(int i = 1; i < n; i++)
        {
            ans = max(ans, dp2[i-1]+dp1[i]);
        }

        printf("%d\n", ans);


    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值