zoukankan      html  css  js  c++  java
  • 最长递增子序列(LIS)

    一:

    很容易想到的 DP的O(N^2)的复杂度

    #pragma comment(linker,"/STACK:102400000,102400000")
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    using namespace std;
    #define clc(a, b) memset(a, b, sizeof(a))
    const int inf = 0x3f;
    const int INF = 0x3f3f3f3f;
    const int maxn = 1000;
    int n, a[maxn], dp[maxn];
    
    int LIS()
    {
        int i, j, k = 0;
        for(i = 0; i < n; i++)
        {
            dp[i] = 1;
            for(j = 0; j < i; j++)
            {
                if(a[i] > a[j] && dp[i] < dp[j] + 1)
                {
                    dp[i] = dp[j] + 1;
                }
            }
            k = dp[i] > k ? dp[i] : k;
        }
        return k;
    }
    int main()
    {
        while(~scanf("%d", &n))
        {
            clc(dp, 0);
            for(int i = 0; i < n; i++) 
                scanf("%d", &a[i]);
            printf("LIS = ");
            printf("%d
    ", LIS());
        }
    }
    

    二: 扩展升级版, 求定长的上升子序列个数

    #pragma comment(linker,"/STACK:102400000,102400000")
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    using namespace std;
    #define clc(a, b) memset(a, b, sizeof(a))
    const int inf = 0x3f;
    const int INF = 0x3f3f3f3f;
    const int maxn = 1000;
    const int mod = 1000000007;
    int n, m, a[maxn], dp[maxn][maxn], sum[maxn];
    //sum 记录长度为i的子序列个数 dp[i][j] 记录从i开始长度为j的个数
    int LIS()
    {
        int i, j, k;
        for(i = 1; i <= n; i++)
        {
            dp[i][1] = 1;
            sum[1] = (dp[i][1] + sum[1]) % mod;
            for(k = 2; k <= i; k++)
            {
                for(j = 1; j < i; j++)
                {
                    if(a[i] > a[j])
                    {
                        dp[i][k] = (dp[i][k] + dp[j][k-1]) % mod;
                    }
                }
                sum[k] = (sum[k] + dp[i][k]) % mod;
                //printf("i = %d, sum[%d] = %d
    ", i, k, sum[k]);
            }
        }
        return 0;
    }
    int main()
    {
        int q;
        while(~scanf("%d %d", &n, &q))//n 数组长度, q个询问
        {
            clc(dp, 0);
            clc(sum, 0);
            for(int i = 1; i <= n; i++) 
                scanf("%d", &a[i]);
            LIS();
            while(q--)
            {
                scanf("%d", &m);
                printf("%d
    ", sum[m]);
            }
        }
        return 0;
    }
    

    三: DP + 二分法

    链接: 原理+解释很详细http://www.felix021.com/blog/read.php?1587

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    
    using namespace std;
    
    const int inf = 0x3f;
    const int INF = 0x3f3f3f3f;
    const int maxn = 1e5+5;
    
    int lis[maxn], a[maxn], n;
    
    int BinSearch(int len, int x)
    {
        int left = 0, right = len - 1;
        while(left <= right)
        {
            int mid = (left + right) / 2;
            if(lis[mid] <= x)
            {
                left = mid + 1;
            }
            else 
            {
                right = mid - 1;
            }
        }
        return left;
    }
    int LIS()
    {
        lis[0] = a[0];
        int len = 1;
        for(int i = 1; i < n; i++)
        {
            if(a[i] > lis[len-1])
            {
                lis[len++] = a[i];
            }
            else
            {
                int pos = BinSearch(len, a[i]);
                lis[pos] = a[i];
            }
        }
        return len;
    }
    int main()
    {
        while(~scanf("%d", &n))
        {
            for(int i = 0; i < n; i++)
            {
                scanf("%d", &a[i]);
            }
    
            int ans = LIS();
            printf("%d
    ", ans);
        }
    }
    

      

  • 相关阅读:
    删数问题
    八中公司_二分图带权最大匹配模板题
    完美子图(这道题太难了,得写下来要不回头又忘了)
    最近集训的图论(思路+实现)题目汇总(内容包含tarjan、分层图、拓扑、差分、奇怪的最短路):
    方格取数(简单版)+小烈送菜(不知道哪来的题)-----------奇怪的dp增加了!
    单调队列优化题:最大数(P1198)
    单调队列+线性dp题Watching Fireworks is Fun (CF372C)
    关于看了几道洛谷灰题(暂无评定)的感想
    洛谷的奇妙今日运势
    互不侵犯(洛谷P1896)
  • 原文地址:https://www.cnblogs.com/tenlee/p/4539494.html
Copyright © 2011-2022 走看看