• 洛谷 题解 P1736 【创意吃鱼法】


    题目大意

    给出一个 (n imes m (1 leq n, m leq 2500))(01) 矩阵,让你在其中找到一个最大的子矩阵使得该子矩阵除了一条对角线上的数字均为 (1) 之外,其他数字均为 (0)

    思路

    Level 1

    暴力枚举每一个子矩阵,然后判断该矩阵是否为正方形且满足要求。
    时间复杂度十分可观地达到了 $ O(n^3 m^3) ≈ O(n^6)$

    Level 1.5

    可以在 Level 1 的基础上,在枚举的时候就保证构造了正方形,时间复杂度 $ O(nm imes min(n, m)^3) ≈ O(n^5)$

    Level 2

    可以用 $ DP $ ,这里给出正方形的 (1) 对角线是从左下角到右上角的情况(例如:
    如果能够继承右上角的方格,那么 (f[i][j] = f[i - 1][j + 1] + 1)
    否则,可以 (O(n)) 枚举一下可以继承多少。
    最坏时间复杂度 (O(n^3)),调的好可以过此题。

    Level 2.5

    可以用前缀和优化,在判断能够继承多少的时候用二分,最坏时间复杂度 (O(n^2 log_{{ }_2}n)),基本上可以过此题。

    Level 3

    <-- 正解警告 -->

    预处理出每个格子最多可以向左,向上,向右延伸多少个格子,使这些格子中的数都是 (0) (不包括这个格子)
    然后对于每个格子,尝试以这个格子为左下角(右下角)建立一个子矩阵,不行就继承上一次 (DP) 的结果。
    (f[i][j]) 表示以 (i, j) 为左下角(右下角)建立的子矩阵的大小。
    (在实际实现的时候,两次 (DP) 的结果被我放在了同一个数组里面)

    Code

    #include <iostream>
    #include <algorithm>
    #include <stdio.h>
    #include <string.h>
    #define Max_N 103
    using namespace std;
    
    template <typename Int>
    Int read() {
    	char ch = getchar();
    	while (!isdigit(ch)) ch = getchar();
    	Int a = (ch & 15);
    	ch = getchar();
    	while (isdigit(ch)) {
    		a = (a + (a << 2) << 1) + (ch & 15);
    		ch = getchar();
    	}
    	return a;
    }  
    
    int n, m, a[2503][2503]; 
    int lef[2503][2503] = {0}, upp[2503][2503] = {0}, rig[2503][2503] = {0};
    int f[2503][2503] = {0};
    
    int main()  
    {   
    	n = read<int>();
    	m = read<int>();
    	for (register int i = 1; i <= n; i++) {
    		for (register int j = 1; j <= m; j++) {
    			a[i][j] = read<int>();
    			if (!a[i][j]) {
    	            lef[i][j] = lef[i][j - 1] + 1;
    	            upp[i][j] = upp[i - 1][j] + 1;
    	        }
    		} 
    	}
    	for (register int i = 1; i <= n; i++) {
    		for (register int j = m; j >= 1; j--) {
    			if (!a[i][j]) {
    	            rig[i][j] = rig[i][j + 1] + 1;
    	        }
    		} 
    	}
    	register int ans = 0;
    	for (register int i = 1; i <= n; i++) {
    		for (register int j = 1; j <= m; j++) if (a[i][j]) {
    			f[i][j] = min(min(lef[i][j - 1], upp[i - 1][j]), 
    						  f[i - 1][j - 1]) + 1;
    			if (f[i][j] > ans) ans = f[i][j];
    		}
    	}
    	memset(f, 0, sizeof(f));
    	for (register int i = 1; i <= n; i++) {
    		for (register int j = m; j >= 1; j--) if (a[i][j]) {
    			f[i][j] = min(min(rig[i][j + 1], upp[i - 1][j]), 
    						  f[i - 1][j + 1]) + 1;
    			if (f[i][j] > ans) ans = f[i][j];
    		}
    	}
    	printf("%d", ans);
        return 0;  
    }
    

    最后,祝你们好运!

  • 相关阅读:
    2012年互联网教育行业观察
    SharePoint 2013的简单介绍
    让Node.js在Azure上运行3
    让Node.js在Azure上运行2
    有一个字符串 "I am a good man",设计一个函数,返回 "man good a am I"。
    json序列化与反序列化
    golang连接mysql数据库进行查询
    简单的WCF服务
    百钱买百鸡问题
    大叔程序员的第九天 @广播启动Activity
  • 原文地址:https://www.cnblogs.com/hkxadpall/p/10066609.html
Copyright © 2020-2023  润新知