刷題記錄【ZJOI2007棋盤製作】二維DP,懸線法。。。
https://www.luogu.org/problemnew/show/P1169
題目描述
國際象棋是世界上最古老的博弈遊戲之一,和中國的圍棋、象棋以及日本的將棋同享盛名。據說國際象棋起源於易經的思想,棋盤是一個
大小的黑白相間的方陣,對應八八六十四卦,黑白對應陰陽。
而我們的主人公小Q,正是國際象棋的狂熱愛好者。作為一個頂尖高手,他已不滿足於普通的棋盤與規則,於是他跟他的好朋友小W決定將棋盤擴大以適應他們的新規則。
小Q找到了一張由
個正方形的格子組成的矩形紙片,每個格子被塗有黑白兩種顏色之一。小Q想在這種紙中裁減一部分作為新棋盤,當然,他希望這個棋盤儘可能的大。
不過小Q還沒有決定是找一個正方形的棋盤還是一個矩形的棋盤(當然,不管哪種,棋盤必須都黑白相間,即相鄰的格子不同色),所以他希望可以找到最大的正方形棋盤面積和最大的矩形棋盤面積,從而決定哪個更好一些。
於是小Q找到了即將參加全國資訊學競賽的你,你能幫助他麼?
輸入輸出格式
輸入格式:
包含兩個整數N和M,分別表示矩形紙片的長和寬。接下來的N行包含一個N ×M的01矩陣,表示這張矩形紙片的顏色(0表示白色,1表示黑色)。
輸出格式:
包含兩行,每行包含一個整數。第一行為可以找到的最大正方形棋盤的面積,第二行為可以找到的最大矩形棋盤的面積(注意正方形和矩形是可以相交或者包含的)。
第一次接觸這種型別的二維dp
因為過於水不得不在閱讀過下面這篇論文之後才AC掉
https://blog.csdn.net/clover_hxy/article/details/50532289
自閉了
程式碼
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define N 2005
#define ll long long
#define right wrong
#define left niconico
int f[N][N],height[N][N],left[N][N],right[N][N],n,m,ans1,ans2,map[N][N];
inline int p2(int x){return x*x;}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1 ; i <= n ; i ++)
{
for(int j = 1 ; j <= m ; j ++)
{
scanf("%d",&map[i][j]);
left[i][j]=right[i][j]=j;
height[i][j]=1;
}
}
for(int i = 0; i <= n; i ++ )map[i][0]=-1;
for(int j = 1; j <= m; j ++ )map[0][j]=-1;
for(int i = 1; i <= n ; i ++)
for(int j = 1; j <= m ; j ++)
{
if(map[i][j]+map[i][j-1]==1)left[i][j]=left[i][j-1];
}
for(int i = 1; i <= n ; i ++)
for(int j = m; j >= 1 ; j --)
{
if(map[i][j]+map[i][j-1]==1)right[i][j-1]=right[i][j];
}
for(int i = 1 ; i <= n; i ++)
for(int j = 1 ; j <= m; j ++)
{
if(map[i][j]+map[i-1][j]==1)
{
height[i][j]=height[i-1][j]+1;
left[i][j]=max(left[i][j],left[i-1][j]);
right[i][j]=min(right[i][j],right[i-1][j]);
}
}
for(int i = 1; i <= n ; i ++)
for(int j = 1 ; j <= m ; j ++)
{
ans1 = max(ans1,height[i][j]*(right[i][j]-left[i][j]+1));
ans2 = max(ans2,p2(min(height[i][j],right[i][j]-left[i][j]+1)));
}
printf("%d\n%d",ans2,ans1);
}
最後想一想還是寫一下思路吧
首先,懸線法的本質是列舉每一個點為下端點的最大懸線,將懸線左右移動,所能移動的最長區間長度即為最大矩形的一邊長。而懸線的長即為另一邊長。
由於懸線移動的時間複雜度為
,所以不滿足本題要求。為了能在O(1)時間內求出最大區間長,我們可以採用預處理的方法。
用陣列left[i][j],right[i][j]表示從i,j開始最靠左、右的符合要求區間終點。
則先遞推求出長度為1的懸線對應的left[i][j],right[i][j],
再按照
進行遞推
最後列舉所有的i,j
則I,j對應的矩形面積為
正方形面積為