zoukankan      html  css  js  c++  java
  • LIS最长上升子序列

    题意:有一个长为n的数列,求出这个序列中最长的上升子序列长度(不连续,不能等于)。

    解法1:简单dp(n2
    思路:

    状态设计:F [ i ] 代表以 A [ i ] 结尾的 LIS 的长度

    状态转移:F [ i ] = max { F [ j ] + 1 ,F [ i ] } (1 <= j <  i,A[ j ] < A[ i ])

    边界处理:F [ i ] = 1 (1 <= i <= n)

     1 const int maxn = 103, INF = 0x7f7f7f7f;
     2 int a[maxn], f[maxn];
     3 int n,ans = -INF;
     4 int main()
     5 {
     6     scanf("%d", &n);
     7     for(int i=1; i<=n; i++) 
     8     {
     9         scanf("%d", &a[i]);
    10         f[i] = 1;
    11     }
    12     for(int i=1; i<=n; i++)
    13         for(int j=1; j<i; j++)
    14             if(a[j] < a[i])
    15                 f[i] = max(f[i], f[j]+1);
    16     for(int i=1; i<=n; i++) 
    17         ans = max(ans, f[i]);
    18     printf("%d
    ", ans);
    19     return 0;
    20 }

    解法2:贪心优化(nlogn)

    思路:新建一个 low 数组,low [ i ]表示长度为i的LIS结尾元素的最小值。

    注意这里的最小值需要更新,而且因为长度为3的LIS结尾元素最小值(low[3])必定大于长度为2的LIS结尾元素最小值(low[4]),所以这个序列就是递增的。

    当面对一个数字arr[i],若其大于low[i]数组最后一个值,则增加数组长度并且将其填到最后面。否则更新low[i],更新的时候我们由于单调递增可以二分找位置。

    1 /* ********************************************** */
    2     int k = 1;
    3     dp[k] = arr[1];
    4     for(int i = 2; i <= n; i++){
    5         if(dp[k] < arr[i]) dp[++k] = arr[i]; //如果比最后一个元素大,那么就添加再最后末尾处
    6         else *(lower_bound(dp + 1, dp + 1 + k, arr[i])) = arr[i]; //如果比最后一个元素小,那么就替换该序列第一个比他大的数;
    7     }
    8  /* ********************************************** */

    POJ3616
    题意:有M个时间段,给你每个时间段的开始和结束时间,还有这个时间段的产量,每个时间段不能重合,且这个时间段用完之后在一定时间内不能再生产,问你怎样选择可以使得最后产量最大。

    解法:带权的LIS,长度相当于时间段的产量,时间段相当于个数,dp跑即可

     1 struct COW {
     2     int l, r, len;
     3     bool operator<(COW &rhs) const {
     4         return l == rhs.l ? r < rhs.r : l < rhs.l;
     5     }
     6 } cow[MAXN];
     7 int N, M, R, ans = -1;
     8 int f[MAXN];
     9 int main() {
    10     // freopen("input.txt", "r", stdin);
    11     scanf("%d %d %d", &N, &M, &R);
    12     rep(i, 1, M) scanf("%d %d %d", &cow[i].l, &cow[i].r, &cow[i].len);
    13     sort(cow + 1, cow + 1 + M);
    14     rep(i, 1, M) {
    15         f[i] = cow[i].len;
    16         rep(j, 1, i - 1) if (cow[j].r + R <= cow[i].l) {
    17             f[i] = max(f[i], f[j] + cow[i].len);
    18         }
    19     }
    20     rep(i, 1, M) ans = max(ans, f[i]);
    21     printf("%d", ans);
    22     return 0;
    23 }

    POJ1065

    题意:有N个木棒,起点和终点分别为 stick[i].l 和 stick[i].r ,要将这些木棒排成不下降的序列,问最少能排成几个这样的序列。

    如:( 9 , 4 ) , ( 2 , 5 ) , ( 1 , 2 ) , ( 5 , 3 ) , 和 ( 4 , 1 ) 这5根木棒,那么最少的方案是:( 4 , 1 ) , ( 5 , 3 ) , ( 9 , 4 ) , ( 1 , 2 ) , ( 2 , 5 )。 共需要两根

    解法:通过鸽巢原理将题目转换为LIS问题。

    为了便于理解,首先我们将所有的木棒按照起点的降序排列,我们设此基础下终点 r 的 LIS 长度为 L,我们先将LIS中包含的木棒都挖出来,形成“空穴”。

    接下来假设问题的答案是将这一堆木棒分成 x 份,假如 x < L,那么根据鸽巢原理一定存在某堆木棒会有大于等于两个空穴。此时任选LIS中的两个元素放入,他们满足 stick[i].r <= stick[i+1].r 为升序,但是当前的木棒是按照起点降序的排列,此时出现了矛盾,所以木棒分成的分数一定等于木棒终点 r 的 LIS 长度。

    代码里面反着写的,意思一样。

     1 int T, N;
     2 struct STICK {
     3     int l, r;
     4     bool operator<(const STICK& rhs) const {
     5         return l == rhs.l ? r <= rhs.r : l < rhs.l;
     6     }
     7 } stick[MAXN];
     8 int dp[MAXN];
     9 
    10 int main() {
    11     // freopen("input.txt", "r", stdin);
    12     scanf("%d", &T);
    13     while (T--) {
    14         CLR(dp);
    15         scanf("%d", &N);
    16         for (int i = 1; i <= N; i++) scanf("%d%d", &stick[i].l, &stick[i].r);
    17         sort(stick + 1, stick + N + 1);
    18         for (int i = 1; i <= N; i++) {
    19             dp[i] = 1;
    20             for (int j = 1; j < i; j++)
    21                 if (stick[j].r > stick[i].r) {
    22                     dp[i] = max(dp[i], dp[j] + 1);
    23                 }
    24         }
    25         int ans = -1;
    26         for (int i = 1; i <= N; i++) ans = max(ans, dp[i]);
    27         printf("%d
    ", ans);
    28     }
    29     return 0;
    30 }
  • 相关阅读:
    Bot Style Tests VS Page Objects
    Qemu文档
    PlantUML
    include <xxx.h> 和 include "xxxx.h"的区别
    2021.40 喜欢当下
    2021.39 MIUI崩溃
    2021.38 聚焦
    2021.37 心流
    2021.36 负熵
    2021.35 精神熵
  • 原文地址:https://www.cnblogs.com/romaLzhih/p/11415303.html
Copyright © 2011-2022 走看看