BZOJ 1057 悬线法求最大01矩阵

1057: [ZJOI2007]棋盘制作

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 3917  Solved: 2046
[Submit][Status][Discuss]

Description

 

  国际象棋是世界上最古老的博弈游戏之一,和中国的围棋、象棋以及日本的将棋同享盛名。据说国际象棋起源 于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳。而我们的主人公小Q, 正是国际象棋的*爱好者。作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W决定 将棋盘扩大以适应他们的新规则。小Q找到了一张由N*M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种 颜色之一。小Q想在这种纸中裁减一部分作为新棋盘,当然,他希望这个棋盘尽可能的大。不过小Q还没有决定是找 一个正方形的棋盘还是一个矩形的棋盘(当然,不管哪种,棋盘必须都黑白相间,即相邻的格子不同色),所以他 希望可以找到最大的正方形棋盘面积和最大的矩形棋盘面积,从而决定哪个更好一些。于是小Q找到了即将参加全 国信息学竞赛的你,你能帮助他么?

Input

  第一行包含两个整数N和M,分别表示矩形纸片的长和宽。接下来的N行包含一个N * M的01矩阵,表示这张矩形 纸片的颜色(0表示白色,1表示黑色)。

Output

  包含两行,每行包含一个整数。第一行为可以找到的最大正方形棋盘的面积,第二行为可以找到的最大矩形棋 盘的面积(注意正方形和矩形是可以相交或者包含的)。

Sample Input

3 3
1 0 1
0 1 0
1 0 0

Sample Output

4
6

HINT

 

N, M ≤ 2000

 

Source

复杂度:O(n * m)

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <string>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <stack>
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <list>
16 #include <iomanip>
17 #include <cctype>
18 #include <cassert>
19 #include <bitset>
20 #include <ctime>
21 
22 using namespace std;
23 
24 #define pau system("pause")
25 #define ll long long
26 #define pii pair<int, int>
27 #define pb push_back
28 #define pli pair<ll, int>
29 #define pil pair<int, ll>
30 #define clr(a, x) memset(a, x, sizeof(a))
31 
32 const double pi = acos(-1.0);
33 const int INF = 0x3f3f3f3f;
34 const int MOD = 1e9 + 7;
35 const double EPS = 1e-9;
36 
37 /*
38 #include <ext/pb_ds/assoc_container.hpp>
39 #include <ext/pb_ds/tree_policy.hpp>
40 using namespace __gnu_pbds;
41 #define TREE tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update>
42 TREE T;
43 */
44 
45 
46 int n, m, mmp[2015][2015], ans1, ans2;
47 int h[2015][2015], l[2015][2015], r[2015][2015];
48 int main() {
49     scanf("%d%d", &n, &m);
50     for (int i = 1; i <= n; ++i) {
51         for (int j = 1; j <= m; ++j) {
52             scanf("%d", &mmp[i][j]);
53         }
54     }
55     for (int i = 1; i <= n; ++i) {
56         for (int j = 1; j <= m; ++j) {
57             if (j > 1 && mmp[i][j - 1] != mmp[i][j]) {
58                 l[i][j] = l[i][j - 1];
59                 r[i][j] = r[i][j - 1];
60             } else {
61                 l[i][j] = j;
62                 int k;
63                 for (k = j + 1; k <= m; ++k) {
64                     if (mmp[i][k] == mmp[i][k - 1]) break;
65                 }
66                 r[i][j] = k - 1;
67             }
68         }
69         for (int j = 1; j <= m; ++j) {
70             if (i > 1 && mmp[i - 1][j] != mmp[i][j]) {
71                 h[i][j] = h[i - 1][j] + 1;
72                 l[i][j] = max(l[i][j], l[i - 1][j]);
73                 r[i][j] = min(r[i][j], r[i - 1][j]);
74             } else {
75                 h[i][j] = 1;
76             }
77             ans2 = max(ans2, h[i][j] * (r[i][j] - l[i][j] + 1));
78             int d = min(h[i][j], r[i][j] - l[i][j] + 1);
79             ans1 = max(ans1, d * d);
80         }
81     }
82     printf("%d\n%d\n", ans1, ans2);
83     return 0;
84 }

 

上一篇:这是Java教程中的错字吗?


下一篇:使用具有(模拟的)可选/默认参数的函数编写Javadoc