zoukankan      html  css  js  c++  java
  • POJ 1769 Minimizing maximizer ( 线段树 && DP )

    题意 : 给定一个区间长度 n ,接下来给出 m 个子区间,要求最少选出多少个区间才能使得 1~n 这个区间被所选的所有子区间覆盖

    分析 : 

    暴力枚举所有可能的组合可以达到 O( m^m ) ,完全不行

    这里考虑动态规划解法

    定义 dp[i][j] : 到第 i 个为止,完全覆盖点(即从 1~这个点都能保证被覆盖)到达第 j 个位置所需的最少子区间

    则初始化为 dp[0][2~n] = INF、dp[0][1] = 0

    假设当前第 i 个子区间用 ( si,ti ) 表示

    则状态转移方程为

    (ti ≠ j) ==> dp[i+1][j] = dp[i][j]

    (ti = j) ==> dp[i+1][j] = min( dp[i][j],min( dp[i][j'] )+1 ) ( si ≤ j' ≤ ti )

    可以看出如果当前计算的是第 i 个则 dp 方程只和 i-1 有关系,所以可以用一维数组来优化空间

    dp[ti] = min( dp[ti],min( dp[j'] ) + 1 ) ( si ≤ j' ≤ ti )

    而如果是要求找出一个区间的最小值的话,我们可以使用线段树来维护,让复杂度降到 logn 级别

    #include <cstdio>
    #include <algorithm>
    #include <string.h>
    using namespace std;
    #define lson l , m , rt << 1
    #define rson m + 1 , r , rt << 1 | 1
    const int maxn = 5e4 + 10;//maxn = 线段的最大长度 则=> maxn<<2 = 线段树可能的最多结点
    const int INF = 0x3f3f3f3f;
    int minv[maxn<<2];//保存最小值
    int dp[maxn];
    int L[500005], R[500005];
    
    void PushUP(int rt) { minv[rt] = min(minv[rt<<1], minv[rt<<1|1]); }
    void build(int l,int r,int rt) {//设置初始值
        if (l == r) {
            minv[rt] = INF;
            return ;
        }
        int m = l + ((r - l)>>1);
        build(lson);
        build(rson);
        PushUP(rt);
    }
    void update(int p,int sc,int l,int r,int rt) {//单点更新,参数(更新点,更新值,总区间左端点,总区间右端点,根节点编号)
        if (l == r) {
            minv[rt] = sc;
            return ;
        }
        int m = l + ((r - l)>>1);
        if (p <= m) update(p , sc , lson);
        else update(p , sc , rson);
        PushUP(rt);
    }
     int query(int L,int R,int l,int r,int rt) {//查询最大值的写法、最小值同理、求和区间写法在下面
         if (L <= l && r <= R)
             return minv[rt];
    
         int m = (l + r) >> 1;
         int ret = INF;
         if (L <= m) ret = min(ret , query(L , R , lson));
         if (R > m) ret = min(ret , query(L , R , rson));
         return ret;
     }
    
    int main(void)
    {
        int len, n;
        while(~scanf("%d %d", &len, &n)){
            for(int i=1; i<=n; i++)
                scanf("%d %d", &L[i], &R[i]);
            build(1, len, 1);
            for(int i=1; i<=len; i++)
                dp[i] = INF;
            dp[1] = 0;
            update(1, 0, 1, len, 1);
            for(int i=1; i<=n; i++){
                int val = query(L[i], R[i], 1, len, 1) + 1;
                if(val < dp[R[i]]){
                    //printf("%d %d
    ", L[i], R[i]);
                    update(R[i], val, 1, len, 1);
                    dp[R[i]] = val;
                }
            }
            printf("%d
    ", dp[len]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    main 函数返回值
    软件架构师必备能力
    Thinkpad S430 3364-A59 (笔记本型号)加内存条过程
    Mysql char(10) 与 varchar(10)的区别
    centos6.5 安装openresty
    AndroidStudio不自己主动加入新创建的文件到VCS
    【HDU 5647】DZY Loves Connecting(树DP)
    linux 新进程的创建
    如何处理Android中的防缓冲区溢出技术
    nyoj 119士兵杀敌(三)(线段树区间最值查询,RMQ算法)
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/8331501.html
Copyright © 2011-2022 走看看