作为比较经典的算法思想,动态规划恐怕早已深入人心。今天在网上找了一个 题目来练练手。
题目大意:
给出一个 数字序列,求出最大的两个不连续子串之和 。
这道题 看似 就是 最大子序列和 的一个变种。本质都是用 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; }
检查了好几遍,发现没问题。
终于发现是 因为 cin,cout,用scanf,printf代替就行。
所以,做 POJ,HDU,ACM的题目还是 用 scanf,printf 时间 快一点。