1. 程式人生 > >[luogu P1169] [ZJOI2007]棋盤制作

[luogu P1169] [ZJOI2007]棋盤制作

題目 oid -m gis max 規則 輸出格式 pac sizeof

[luogu P1169] [ZJOI2007]棋盤制作

題目描述

國際象棋是世界上最古老的博弈遊戲之一,和中國的圍棋、象棋以及日本的將棋同享盛名。據說國際象棋起源於易經的思想,棋盤是一個8*8大小的黑白相間的方陣,對應八八六十四卦,黑白對應陰陽。

而我們的主人公小Q,正是國際象棋的狂熱愛好者。作為一個頂尖高手,他已不滿足於普通的棋盤與規則,於是他跟他的好朋友小W決定將棋盤擴大以適應他們的新規則。

小Q找到了一張由N*M個正方形的格子組成的矩形紙片,每個格子被塗有黑白兩種顏色之一。小Q想在這種紙中裁減一部分作為新棋盤,當然,他希望這個棋盤盡可能的大。

不過小Q還沒有決定是找一個正方形的棋盤還是一個矩形的棋盤(當然,不管哪種,棋盤必須都黑白相間,即相鄰的格子不同色),所以他希望可以找到最大的正方形棋盤面積和最大的矩形棋盤面積,從而決定哪個更好一些。

於是小Q找到了即將參加全國信息學競賽的你,你能幫助他麽?

輸入輸出格式

輸入格式:

包含兩個整數N和M,分別表示矩形紙片的長和寬。接下來的N行包含一個N * M的01矩陣,表示這張矩形紙片的顏色(0表示白色,1表示黑色)。

輸出格式:

包含兩行,每行包含一個整數。第一行為可以找到的最大正方形棋盤的面積,第二行為可以找到的最大矩形棋盤的面積(註意正方形和矩形是可以相交或者包含的)。

輸入輸出樣例

輸入樣例#1:
3 3
1 0 1
0 1 0
1 0 0
輸出樣例#1:
4
6

說明

對於20%的數據,N, M ≤ 80

對於40%的數據,N, M ≤ 400

對於100%的數據,N, M ≤ 2000

好久都沒有寫極大化了。。。

你只要根據每個點的坐標(i,j) i+j的奇偶性和顏色xor一下,就會發現,相鄰兩個不同色的棋子變成了同色。

那麽我們可以通過做2次極大化——分別以1為障礙點,以0為障礙點找出最大的全0矩陣和全1矩陣。

正方形一定包含在矩陣裏面,也非常好算。

code:

技術分享
 1 %:pragma GCC optimize(2)
 2 #include<bits/stdc++.h>
 3 #define R register
 4 #define Ms(a,x) memset(a,x,sizeof a)
 5
using namespace std; 6 const int N=2005; 7 int n,m,ans1,ans2,u[N],l[N],r[N]; bool a[N][N]; 8 inline int read() { 9 int x=0; char ch=getchar(); 10 while (ch<0||ch>9) ch=getchar(); 11 return ch-0; 12 } 13 void calc(bool aim) { 14 Ms(r,63); 15 for (R int i=1,las; i<=n; i++) { 16 las=1; 17 for (R int j=1; j<=m; j++) 18 if (a[i][j]!=aim) las=j+1,u[j]=l[j]=0; 19 else u[j]++,l[j]=max(las,l[j]); 20 las=m; 21 for (R int j=m; j>=1; j--) 22 if (a[i][j]!=aim) las=j-1,r[j]=m; 23 else r[j]=min(las,r[j]); 24 for (R int j=1,e; j<=m; j++) if (a[i][j]==aim) { 25 e=min(u[j],(r[j]-l[j]+1)); 26 ans1=max(ans1,e*e); 27 ans2=max(ans2,u[j]*(r[j]-l[j]+1)); 28 } 29 } 30 } 31 int main() { 32 cin>>n>>m,ans1=ans2=1; 33 for (R int i=1; i<=n; i++) 34 for (R int j=1; j<=m; j++) a[i][j]=read()^(i+j)&1; 35 calc(0),calc(1); 36 printf("%d\n%d\n",ans1,ans2); 37 return 0; 38 }
View Code

[luogu P1169] [ZJOI2007]棋盤制作