1. 程式人生 > >BZOJ 1057 懸線法求最大01矩陣

BZOJ 1057 懸線法求最大01矩陣

主人公 https mat 棋盤制作 找到 http fstream 國際象棋 最大

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 }

BZOJ 1057 懸線法求最大01矩陣