洛谷P1169 [ZJOI2007]棋盘制作解题报告

题目描述

国际象棋是世界上最古老的博弈游戏之一,和中国的围棋、象棋以及日本的将棋同享盛名。据说国际象棋起源于易经的思想,棋盘是一个8×8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳。

而我们的主人公小Q,正是国际象棋的狂热爱好者。作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W决定将棋盘扩大以适应他们的新规则。

小Q找到了一张由N×M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一。小Q想在这种纸中裁减一部分作为新棋盘,当然,他希望这个棋盘尽可能的大。

不过小Q还没有决定是找一个正方形的棋盘还是一个矩形的棋盘(当然,不管哪种,棋盘必须都黑白相间,即相邻的格子不同色),所以他希望可以找到最大的正方形棋盘面积和最大的矩形棋盘面积,从而决定哪个更好一些。

于是小Q找到了即将参加全国信息学竞赛的你,你能帮助他么?

 

其实这就是个悬线法,就像我们人工找最大矩阵一样,先找一块空的地方

 

洛谷P1169 [ZJOI2007]棋盘制作解题报告_第1张图片(红色为不能到达的地方)洛谷P1169 [ZJOI2007]棋盘制作解题报告_第2张图片粉色是随便找的一个点(为什么用粉色?粉色可爱嘛。)

洛谷P1169 [ZJOI2007]棋盘制作解题报告_第3张图片先向右走,只能到达最右的点,同理左边只能到达左边的点

至于上下,因为我们是先从左向右扫,扫完第一行才扫第二行,因此第二行的长度可以从第一行上转移过来,就有up[i][j]= up[i-1][j]+1;最终求面积只要。

矩形:(rght[i][j]-lft[i][j]+1)*up[i][j] //记得加一,左边那一个不能忘掉。

正方形:只要在min(rght[i][j]-lft[i][j]+1,up[i][j])之间去最小值再平方就行了。

总的时间复杂度(NM),空间复杂度(NM),

如果任想继续深入,可以阅读这篇文章。https://blog.csdn.net/clover_hxy/article/details/50532289?locationNum=1&fps=1

(膜拜大神~~~~~~~~~~~~~~~~~~~~~~~~)

最后附上鄙人弱弱的代码

a[i][j]储存图的信息

up[i][j]代表第i,j点所能到达最大高度         up[i][j]= up[i-1][j]+1

rght[i][j]代表第i,j点所能到达最右的地方           rght[i][j]=min(rght[i][j],rght[i-1][j])

lft[i][j]代表第i,j点所能到达最左的地方             lft[i][j]= max(lft[i][j],lft[i-1][j])

#include 
#include 
#include 
#include 
#define re register int 
using namespace std;
const int maxn = 2005;
int a[maxn][maxn],n,m,up[maxn][maxn],lft[maxn][maxn],rght[maxn][maxn],ans1,ans2;
inline int read(){
	int x=0,f=1;
	char ch = getchar();
	while(ch<'0'||ch>'9'){if(ch == '-')f=-1; ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
	return x*f;
}

int main(){
	ios::sync_with_stdio(false);
	n=read(); m=read();
	for(re i=1; i<=n; i++){
		for(re j=1; j<=m; j++){
			a[i][j] = read();
			lft[i][j] = rght[i][j] = j;
			up[i][j] = 1;
		}
	}
	for(re i=1;i<=n; i++){
		for(re j=2; j<=m; j++){
			if(a[i][j]+a[i][j-1]==1)
				lft[i][j] = lft[i][j-1];
		}
	}
	for(re i=1; i<=n; i++){
		for(re j=m-1; j; j--){
			if(a[i][j]+a[i][j+1] == 1){
				rght[i][j] = rght[i][j+1];
			}
		}
	}
	for(re i=1; i<=n; i++){
		for(re j=1; j<=m; j++){
			if(i>1&& a[i][j]+a[i-1][j]==1){
				lft[i][j] = max(lft[i][j],lft[i-1][j]);
				rght[i][j] = min(rght[i][j],rght[i-1][j]);
				up[i][j] = up[i-1][j]+1;
			}
			re dist1 = rght[i][j]-lft[i][j]+1;
			re dist2 = min(dist1,up[i][j]);
			ans1 = max(ans1,dist2*dist2);
			ans2 = max(ans2,dist1*up[i][j]);
		}
	} 
	cout << ans1 << endl << ans2 << endl;
	return 0;
}

 

你可能感兴趣的:(悬线法)