bzoj 1057: [ZJOI2007]棋盤製作
阿新 • • 發佈:2019-01-02
1057: [ZJOI2007]棋盤製作
Time Limit: 20 Sec Memory Limit: 162 MB
Submit: 3851 Solved: 2009
[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
裸的懸線法求最大矩陣(雖然單調棧也可以做)
對於每個點,我們記錄最遠能到的左端點
然後……還是看程式碼理解一下吧
/**************************************************************
Problem: 1057
User: lahlah
Language: C++
Result: Accepted
Time:2708 ms
Memory:64100 kb
****************************************************************/
#include<bits/stdc++.h>
#define N 2005
using namespace std;
int n, m, a[N][N], l[N][N], r[N][N], up[N][N], ans1, ans2;
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++) scanf("%d", &a[i][j]), l[i][j] = r[i][j] = j;
for(int i = 1; i <= n; i ++)
for(int j = 2; j <= m; j ++)
if(a[i][j] == !a[i][j-1]) l[i][j] = l[i][j-1];//預處理往左最遠能擴充套件的位置
for(int i = 1; i <= n; i ++)
for(int j = m - 1; j >= 1; j --)
if(a[i][j] == !a[i][j+1]) r[i][j] = r[i][j+1];//預處理往右最遠能擴充套件的位置
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= m; j ++){
up[i][j] = 1;
if(a[i][j] == !a[i-1][j] && i != 1){//如果可以由上面的擴充套件則擴充套件
up[i][j] = up[i-1][j] + 1;
l[i][j] = max(l[i][j], l[i-1][j]);
r[i][j] = min(r[i][j], r[i-1][j]);
}
int w = r[i][j] - l[i][j] + 1, h = up[i][j];//更新答案
ans1 = max(ans1, w * h);
ans2 = max(ans2, min(w, h) * min(w, h));
}
}
printf("%d\n%d", ans2, ans1);
return 0;
}
有意思