百练 2757 最长上升子序列

果然,动态规划的无后效性是和阶段的划分有关的。

受前面的影响,涉及到n个元素的这种题目,我第一想法就是找前k个元素的最优解。

但课件里面说了,这是不满足无后效性的:

 

“求序列的前n个元素的最长上升子序列的长度”是个
子问题,但这样分解子问题,不具有“无后效性”
假设F(n) = x,但可能有多个序列满足F(n) = x。有的
序列的最后一个元素比 an+1小,则加上an+1就能形成更长上
升子序列;有的序列最后一个元素不比an+1小……以后的事
情受如何达到状态n的影响,不符合“无后效性”

 

确定了阶段的划分,状态转移方程还是很好理解的,代码也十分容易实现。

描述

一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1a2, ..., aN),我们可以得到一些上升的子序列(ai1ai2, ..., aiK),这里1 <= i1 < i2 < ... < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).

你的任务,就是对于给定的序列,求出最长上升子序列的长度。

输入

输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。

输出

最长上升子序列的长度。

 

 两种代码实现,“人人为我,我为人人”,这八个字还是很形象的。

人人为我:

状态i的值Fi由若干个值已知的状态值Fk,Fm,..Fy推出,如求和,取最大值……

 1 //#define LOCAL
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 const int maxn = 1010;
 9 int dp[maxn];
10 int a[maxn];
11 
12 int main(void)
13 {
14     #ifdef LOCAL
15         freopen("2757in.txt", "r", stdin);
16     #endif
17 
18     int i, n, j;
19     memset(dp, 0, sizeof(dp));
20     dp[1] = 1;
21     cin >> n;
22     
23     for(i = 1; i <= n; ++i)
24     {
25         scanf("%d", &a[i]);
26         dp[i] = 1;    
27     }
28 
29     for(i = 2; i <= n; ++i)
30         for(j = 1; j < i; ++j)
31         {
32             if(a[j] < a[i])
33             {
34                 dp[i] = max(dp[i], dp[j]+1);
35             }
36         }
37 
38     int ans = 0;
39     for(i = 1; i <= n; ++i)
40         ans = max(ans, dp[i]);
41     printf("%d\n", ans);
42     
43     return 0;
44 }
代码君

我为人人:

状态i的值Fi在被更新(不一定是最终求出)的时候,依据Fi去更新(不一定是最终求出)和状态i相关的其他一些状态的值Fk,Fm,..Fy

 1 //#define LOCAL
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 const int maxn = 1010;
 9 int dp[maxn];
10 int a[maxn];
11 
12 int main(void)
13 {
14     #ifdef LOCAL
15         freopen("2757in.txt", "r", stdin);
16     #endif
17 
18     int i, j, n;
19     scanf("%d", &n);
20     for(i = 1; i <= n; ++i)
21     {
22         scanf("%d", &a[i]);
23         dp[i] = 1;
24     }
25 
26     for(i = 1; i < n; ++i)
27         for(j = i+1; j <= n; ++j)
28         {
29             if(a[j] > a[i])
30             {
31                 dp[j] = max(dp[j], dp[i]+1);
32             }
33         }
34 
35     int ans = dp[1];
36     for(i = 1; i <= n; ++i)
37         ans = max(ans, dp[i]);
38     printf("%d\n", ans);
39 
40     return 0;
41 }
代码君
posted @ 2014-07-17 17:16  AOQNRMGYXLMV  阅读(337)  评论(0编辑  收藏  举报