1. 程式人生 > 其它 >【題解】[ZJOI2007]棋盤製作

【題解】[ZJOI2007]棋盤製作

題目描述

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

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

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

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

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


輸入輸出格式

輸入格式:

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

輸出格式:

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


輸入輸出樣例

輸入樣例

3 3
1 0 1
0 1 0
1 0 0

輸出樣例

4
6

說明

對於 20 % 20\% 20% 的資料, N , M ≤ 80 N,M≤80 N,M80
對於 40 % 40\% 40% 的資料, N , M ≤ 400 N, M ≤ 400 N,M400
對於 100 % 100\% 100% 的資料, N , M ≤ 2000 N, M ≤ 2000 N,M2000


思路

標準懸線法,詳見上一篇部落格【學習筆記】最大子矩形問題


程式碼

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <string> #include <cstdlib> #include <iostream> #include <cmath> #define re register long long #define rep(i,a,b) for(re i=a;i<=b;++i) #define drep(i,a,b) for(re i=a;i>=b;--i) typedef long long ll; using namespace std; inline ll read(){ ll x=0;bool f=0;char ch=getchar(); while(!isdigit(ch)) f^=!(ch^'-'),ch=getchar(); while(isdigit(ch)) x=((x+(x<<2))<<1)+(ch^48),ch=getchar(); return f?-x:x; } ll n,m,height[2050][2050],lft[2050][2050],rit[2050][2050],ansc=0,ansz=0; bool a[2050][2050]; int main(){ n=read(),m=read(); rep(i,1,n) rep(j,1,m){ a[i][j]=read(); height[i][j]=1;//初始化高度值 if(i!=1 and a[i][j]!=a[i-1][j]) height[i][j]=height[i-1][j]+1; if(j!=1 and a[i][j]!=a[i][j-1]) lft[i][j]=lft[i][j-1];//遞推找到左障礙點 else if(j!=1 and a[i][j]==a[i][j-1]) lft[i][j]=j-1; } rep(i,1,n) drep(j,m,1){ rit[i][j]=j; if(j!=m and a[i][j]!=a[i][j+1]) rit[i][j]=rit[i][j+1]; else if(j!=m and a[i][j]==a[i][j+1]) rit[i][j]=j; } /* rep(i,1,n){ rep(j,1,m){ printf("%lld ",rit[i][j]); } puts(""); } */ rep(i,1,n){ rep(j,1,m){ if(i!=1 and a[i][j]!=a[i-1][j]){ lft[i][j]=max(lft[i][j],lft[i-1][j]);//更新左邊界 rit[i][j]=min(rit[i][j],rit[i-1][j]); } // printf("%lld ",height[i][j]); ansc=max(ansc,(rit[i][j]-lft[i][j])*height[i][j]);//長方形面積 ansz=max(ansz,min(rit[i][j]-lft[i][j],height[i][j]));//正方形邊長 } // puts(""); } printf("%lld\n%lld\n",ansz*ansz,ansc); return 0; }

題目來源

洛谷 P1169 [ZJOI2007]棋盤製作