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

题目描述

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

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

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

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

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

 

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

 

(红色为不能到达的地方)粉色是随便找的一个点(为什么用粉色?粉色可爱嘛。)

先向右走,只能到达最右的点,同理左边只能到达左边的点

至于上下,因为我们是先从左向右扫,扫完第一行才扫第二行,因此第二行的长度可以从第一行上转移过来,就有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 <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jack_Mask

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值