百练 2757 最长上升子序列
果然,动态规划的无后效性是和阶段的划分有关的。
受前面的影响,涉及到n个元素的这种题目,我第一想法就是找前k个元素的最优解。
但课件里面说了,这是不满足无后效性的:
“求序列的前n个元素的最长上升子序列的长度”是个
子问题,但这样分解子问题,不具有“无后效性”
假设F(n) = x,但可能有多个序列满足F(n) = x。有的
序列的最后一个元素比 an+1小,则加上an+1就能形成更长上
升子序列;有的序列最后一个元素不比an+1小……以后的事
情受如何达到状态n的影响,不符合“无后效性”
确定了阶段的划分,状态转移方程还是很好理解的,代码也十分容易实现。
描述
一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, ..., aN),我们可以得到一些上升的子序列(ai1, ai2, ..., 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 }