zoukankan      html  css  js  c++  java
  • 悬线法DP总结

    悬线法DP总结

    问题模型

    求满足某种条件(如01交替)的最大矩形(正方形)

    思想

    先预处理出(ml[i][j],mr[i][j],mt[i][j]),分别表示当前位置((i,j))能向左扩展到的最左边的编号、能向右扩展到的最右边的编号、能向上扩展到的最大高度。

    然后在做(DP)时,除第一行,每行根据上一行的状态更新当前状态,逐行扫一遍。复杂度(O(n imes m))

    [USACO5.3]巨大的牛棚Big Barn

    洛谷题面

    题意:求最大正方形

    #include <cstdio>
    #define MAXN 1010
    #define MAX(A,B) ((A)>(B)?(A):(B))
    #define MIN(A,B) ((A)<(B)?(A):(B))
    using namespace std;
    int n,t,ans;
    bool mp[MAXN][MAXN];
    int ml[MAXN][MAXN],mr[MAXN][MAXN],mt[MAXN][MAXN];
    int main()
    {
        scanf("%d %d", &n, &t);
        while(t--){
            int x,y;
            scanf("%d %d", &x, &y);
            mp[x][y]=1;
        }
        for(register int i=1;i<=n;++i){
            for(register int j=1;j<=n;++j){
                ml[i][j]=mr[i][j]=j;
                mt[i][j]=1;
            }
        }
        for(register int i=1;i<=n;++i)
        for(register int j=2;j<=n;++j)
            if(mp[i][j-1]==0&&mp[i][j]==0)
                ml[i][j]=ml[i][j-1]; // 预处理出能向左扩展到的最左边的编号
        for(register int i=1;i<=n;++i)
        for(register int j=n-1;j>=1;--j)
            if(mp[i][j+1]==0&&mp[i][j]==0)
                mr[i][j]=mr[i][j+1]; // 预处理出能向右扩展到的最右边的编号
        for(register int i=1;i<=n;++i)
        for(register int j=2;j<=n;++j){
            if(i>1&&mp[i-1][j]==0&&mp[i][j]==0){ // 除第一行,每行根据上一行的状态更新当前状态
                ml[i][j]=MAX(ml[i][j], ml[i-1][j]); // 注意取MAX,获得合法的ml
                mr[i][j]=MIN(mr[i][j], mr[i-1][j]); // 注意取MIN,获得合法的mr
                mt[i][j]=mt[i-1][j]+1;
            }
            int w=MIN(mr[i][j]-ml[i][j]+1, mt[i][j]); // 因为是正方形
            ans=MAX(ans, w);
        }
        printf("%d", ans);
        return 0;
    }
    

    [ZJOI2007]棋盘制作

    P1169 洛谷题面

    题意:求最大01交替正方形、长方形

    #include <cstdio>
    #define MAXN 2002
    #define INF 0x3fffffff
    #define MAX(A,B) ((A)>(B)?(A):(B))
    #define MIN(A,B) ((A)<(B)?(A):(B))
    using namespace std;
    int n,m,ml[MAXN][MAXN],mr[MAXN][MAXN],mt[MAXN][MAXN];
    int ans1, ans2;
    bool mp[MAXN][MAXN];
    int main()
    {
        scanf("%d %d", &n, &m);
        for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            scanf("%d", &mp[i][j]),ml[i][j]=mr[i][j]=j,mt[i][j]=1;
        for(int i=1;i<=n;++i)
        for(int j=2;j<=m;++j)
            if(mp[i][j]!=mp[i][j-1]) // 01扩展
                ml[i][j]=MIN(ml[i][j-1], ml[i][j]); // 预处理出能向左扩展到的最左边的编号
        for(int i=1;i<=n;++i)
        for(int j=m-1;j>=1;--j)
            if(mp[i][j]!=mp[i][j+1]) // 01扩展
                mr[i][j]=MAX(mr[i][j+1], mr[i][j]); // 预处理出能向右扩展到的最右边的编号
        for(int i=1;i<=n;++i)
        for(int j=2;j<=m;++j){
            if(i>1&&mp[i][j]!=mp[i-1][j]){ // 除第一行,每行根据上一行的状态更新当前状态
                ml[i][j]=MAX(ml[i][j], ml[i-1][j]);
                mr[i][j]=MIN(mr[i][j], mr[i-1][j]);
                mt[i][j]=mt[i-1][j]+1;
            }
            int w = mr[i][j] - ml[i][j]+1;
            int h = mt[i][j];
            ans1 = MAX(MIN(w,h)*MIN(w,h), ans1); // 找出最大合法正方形
            ans2 = MAX(w*h, ans2); // 找出最大合法矩形
        }
        printf("%d
    %d", ans1, ans2);
        return 0;
    }
    

    P4147 玉蟾宫

    P4147 玉蟾宫

    题意:毒瘤输入,求最大正方形

    #include <cstdio>
    #define MAXN 1010
    #define MAX(A,B) ((A)>(B)?(A):(B))
    #define MIN(A,B) ((A)<(B)?(A):(B))
    using namespace std;
    int n,m,ans;
    bool mp[MAXN][MAXN];
    int ml[MAXN][MAXN],mr[MAXN][MAXN],mt[MAXN][MAXN];
    int read(){
        char in=getchar();
        while(in!='F'&&in!='R') in=getchar();
        if(in=='F') return 1;
        return 0;
    }
    int main()
    {
        scanf("%d %d", &n, &m);
        for(register int i=1;i<=n;++i){
            for(register int j=1;j<=m;++j){
                mp[i][j]=read();
                ml[i][j]=mr[i][j]=j;
                mt[i][j]=1;
            }
        }
        for(register int i=1;i<=n;++i)
        for(register int j=2;j<=m;++j)
            if(mp[i][j-1]==1&&mp[i][j]==1)
                ml[i][j]=ml[i][j-1];
        for(register int i=1;i<=n;++i)
        for(register int j=m-1;j>=1;--j)
            if(mp[i][j+1]==1&&mp[i][j]==1)
                mr[i][j]=mr[i][j+1];
        for(register int i=1;i<=n;++i)
        for(register int j=2;j<=m;++j){
            if(i>1&&mp[i-1][j]==1&&mp[i][j]==1){
                ml[i][j]=MAX(ml[i][j], ml[i-1][j]);
                mr[i][j]=MIN(mr[i][j], mr[i-1][j]);
                mt[i][j]=mt[i-1][j]+1;
            }
            int w=mr[i][j]-ml[i][j]+1;
            ans=MAX(ans, w*mt[i][j]);
        }
        printf("%d", 3*ans);
        return 0;
    }
    
  • 相关阅读:
    标准化R包开发流程
    创建Rdemo项目
    rJava在ubuntu上的安装
    Linux初始root密码设置
    检查网卡错误
    统计学习方法-李航 第一章
    ubuntu16.04细节设置
    linux指令学习
    Python在ubuntu16.04上环境搭建
    kuberneets 1.17 设置 kube-reserved, system-reserved
  • 原文地址:https://www.cnblogs.com/santiego/p/10848134.html
Copyright © 2011-2022 走看看