BestCoder16 1002.Revenge of LIS II(hdu 5087) 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5087

题目意思:找出第二个最长递增子序列,输出长度。就是说,假如序列为 1 1 2,第二长递增子序列是1 2(下标为2 3),而第一长递增子序列也是(下标为 1 3)。

    我一开始天真的以为,还是利用求最长递增子序列的算法啦,第二长不就是对dp 数组sort完后(从小到大)的dp[cnt-1] 啦,接着就呵呵啦~~~~= =

    题解说,要加多一个 dp 数组,以便对当前下标值为 i 的数 a[i] 为结尾求出第二条dp序列,如果长度一样就直接那个长度了,否则是长度减 1。一直对每个数这样处理,处理到序列最后一个数就是答案了。

    以下是看别人的。设 dp[i][0] 表示以a[i]这个数为结尾的最长递增子序列的长度,dp[i][1] 表示以a[i]这个数为结尾的第二长递增子序列的长度(可能为dp[i][0],也可能是dp[i][0]-1)

    然后把每个数的两个dp值放进ans数组中,sort之后,答案就为ans[cnt-2]。

   

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 const int N = 1000 + 10;
 9 
10 int a[N], ans[2*N];
11 int dp[N][2];
12 
13 int main()
14 {
15     int T, n;
16     #ifndef ONLINE_JUDGE
17         freopen("input.txt", "r", stdin);
18     #endif
19     while (scanf("%d", &T) != EOF)
20     {
21         while (T--)
22         {
23             scanf("%d", &n);
24             for (int i = 1; i <= n; i++)
25                 scanf("%d", &a[i]);
26             memset(dp, 0, sizeof(dp));
27             int cnt = 0;
28             for (int i = 1; i <= n; i++)
29             {
30                 dp[i][0] = 1;
31                 for (int j = 1; j < i; j++)
32                 {
33                     if (a[j] < a[i])
34                     {
35                         int x = dp[j][0] + 1;
36                         int y = dp[j][1] + 1;
37 
38                         if (x > dp[i][0])
39                             swap(x, dp[i][0]);
40                         dp[i][1] = max(x, dp[i][1]);
41                         dp[i][1] = max(y, dp[i][1]);
42                     }
43                 }
44                 ans[cnt++] = dp[i][0];
45                 ans[cnt++] = dp[i][1];
46             }
47             sort(ans, ans+cnt);
48             printf("%d\n", ans[cnt-2]);
49         }
50     }
51     return 0;
52 }

 

posted @ 2014-11-04 22:07  windysai  阅读(193)  评论(0编辑  收藏  举报