zoukankan      html  css  js  c++  java
  • P1169 [ZJOI2007]棋盘制作 && 悬线法

    P1169 [ZJOI2007]棋盘制作

    给出一个 (N * M)(01) 矩阵, 求最大的正方形和最大的矩形交错子矩阵
    (n , m leq 2000)

    悬线法

    悬线法可以求出给定矩阵中满足条件的最大子矩阵

    对于每个点, 维护 两条等长的线段, 两线段的底部达到此点的纵坐标, 分别代表能从这个点达到的最左 / 最右端点
    大概长这样

       l        r
       |        |
       |        |
       |        |
       |        |
       |    *   |
    

    那么枚举每个点的这两条线段, 不断用 ((r - l + 1) * dis) 更新答案即可
    这就是悬线法

    这两条线段看上去很难维护, 其实不然
    因为其等长, 我们将这两条线段用如下几个属性表示:
    (l[i][j]) 表示从 ((i, j)) 能达到的最左的坐标
    (r[i][j]) 表示从 ((i, j)) 能达到的最右的坐标
    (up[i][j]) 表示 ((i, j)) 向上达到的 最上坐标, 即悬线的长度

    初始化满足条件的每个(1 * 1) 小矩阵 (l[i][j] = r[i][j] = j, up[i][j] = 1), 即围成一个 (1 * 1) 的小小矩形

    容易想到维护悬线可以递推, 在满足矩阵限制的条件下, 先初始化

    [l[i][j] = l[i][j - 1]$$ $$r[i][j] = r[i][j + 1] ]

    比对上一行,在满足矩阵限制的条件下, 我们只能取最窄满足条件

    [l[i][j] = max(l[i][j], l[i - 1][j])$$ $$r[i][j] = min(r[i][j], r[i - 1][j]) ]

    然后悬线长度可以继承上一行的 $$up[i][j] = up[i - 1][j] + 1$$

    有了悬线直接计算围出来的面积即可

    Solution

    此题求最大交错矩阵
    交错矩阵任意相邻两格颜色不同
    于是限制条件即为相邻两格颜色不等
    放个代码理解 悬线法

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #include<climits>
    #define LL long long
    #define REP(i, x, y) for(int i = (x);i <= (y);i++)
    using namespace std;
    int RD(){
        int out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    const int maxn = 2019;
    int lenx, leny;
    int map[maxn][maxn];
    int l[maxn][maxn], r[maxn][maxn];
    int up[maxn][maxn];
    int ans1, ans2;
    void init(){
    	lenx = RD(), leny = RD();
    	REP(i, 1, lenx)REP(j, 1, leny){
    		map[i][j] = RD();
    		l[i][j] = r[i][j] = j;
    		up[i][j] = 1;
    		}
    	REP(i, 1, lenx)REP(j, 2, leny){
    		if(map[i][j] != map[i][j - 1])l[i][j] = l[i][j - 1];//预处理左边界
    		}
    	REP(i, 1, lenx)for(int j = leny - 1;j >= 1;j--){
    		if(map[i][j] != map[i][j + 1])r[i][j] = r[i][j + 1];//右边界
    		}
    	}
    void solve(){
    	REP(i, 1, lenx)REP(j, 1, leny){
    		if(i > 1 && map[i][j] != map[i - 1][j]){
    			l[i][j] = max(l[i][j], l[i - 1][j]);
    			r[i][j] = min(r[i][j], r[i - 1][j]);
    			up[i][j] = up[i - 1][j] + 1;
    			}
    		int a = r[i][j] - l[i][j] + 1;//宽
    		int b = min(a, up[i][j]);
    		ans1 = max(ans1, b * b);
    		ans2 = max(ans2, a * up[i][j]);
    		}
    	printf("%d
    %d
    ", ans1, ans2);
    	}
    int main(){
    	init();
    	solve();
    	return 0;
    	}
    
  • 相关阅读:
    使用XE7并行库中的TTask(转)
    Delphi xe7并行编程快速入门(转)
    Pre-compile (pre-JIT) your assembly on the fly, or trigger JIT compilation ahead-of-time (转)
    使用RemObjects Pascal Script (转)
    Remobjects SDK 服务器搭建
    toString()方法
    环境变量
    jstl标签学习
    SQL的各种join
    Mybatis的一些配置
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9909824.html
Copyright © 2011-2022 走看看