POJ 2479 (动态规划)

作为比较经典的算法思想,动态规划恐怕早已深入人心。今天在网上找了一个 题目来练练手。

题目大意:

给出一个 数字序列,求出最大的两个不连续子串之和 。 

这道题 看似 就是 最大子序列和 的一个变种。本质都是用 DP 来解决。

首先,将 a[i] 表示第 i 个元素,再建立 三个数组 tm[num],sm[num],stm[num]

含义如下: tm[i] 表示 以第i个元素结尾的最大字串;sm[i] 表示以第i个元素开头的最大字串;

最后一个stm比较关键,stm[i] 表示后面 n-i+1 个元素的最大值

这里举个例子:

-1,2,3,4,2,5

一个6个元素,stm[2]表示后面5个元素的最大子串的值(6-2+1)

那么,下面就可以列出状态转移方程:

tm[i] = max{ tm[i-1]+a[i],a[i]}

sm[i] = max{sm[i+1]+a[i],a[i]}

stm[i] = max{stm[i+1],sm[i]}    这个方程的意思是,后面x个数的最大字串的值 = max(后面x-1个数的最大子串的值,以第i个元素开头的最大子串}

说明:状态转移方程只要合理,能解释得清楚,即符合题意。 方程不唯一。

//
//  main.cpp
//  Demo
//
//  Created by Jaster_chen on 1/27/16.
//  Copyright © 2016 Jaster_chen. All rights reserved.
//

#include <iostream>
using namespace std;
#define MAX 50001
#define max(a,b) a>b?a:b

int a[MAX],tm[MAX],sm[MAX],stm[MAX];
//tm表示以i为结尾的最大字串,sm表示以i开始的最大字串,stm[i]表示取后面 num-i+1 个元素最大值

int main()
{
    int T,num,i;
    scanf("%d",&T);
    while(T--){
        cin>>num;
        for(i=1;i<=num;i++){
            scanf("%d",&a[i]);
        }
        tm[1] = a[1];
        for(i=2;i<=num;i++){
            tm[i] = max(tm[i-1]+a[i],a[i]);
        }
        sm[num] = a[num];
        for(i=num-1;i>=1;i--){
            sm[i] = max(sm[i+1]+a[i],a[i]);
        }
        stm[num] = a[num];
        for(i=num-1;i>=1;i--){
            stm[i] = max(stm[i+1],sm[i]);
        }
        int sum;
        sum = tm[1]+stm[2];
        for(i=2;i<=num-1;i++){
            sum = max(sum,tm[i]+stm[i+1]);
        }
        printf("%d\n",sum);
    }
    return 0;
}

代码写完之后,时间复杂度保持在 O(n),但是 在POJ上 总是通不过,说是 时间超时。

检查了好几遍,发现没问题。

终于发现是 因为 cin,cout,用scanf,printf代替就行。

所以,做 POJ,HDU,ACM的题目还是 用 scanf,printf 时间 快一点。

你可能感兴趣的:(C++,动态规划,ACM,poj)