最大正方形(枚举)

枚举算法

1.特点:一一列举
2.要点:不重复不遗漏
但是不充复不遗漏只能保证把题目求出来,但可能会被时间卡住
3.优化:把多余的操作去掉,减少枚举次数
①选择合适的枚举对象
②选择合适的枚举方向——方便排除非法和不是最优的情况
③选择合适的数据维护方法——方便转化问题

最大正方形

题目描述:

在一个N*N(N<=100)矩阵中求一个最大的正方形使得该正方形的四个顶点都是有字符“#”构成。
在这里插入图片描述

解题思路:

首先我们可以暴力做法:枚举四个#,即写一个四重的for循环,去看这个四个#,把这四个#找出来之后去看他是否能组成一个正方形。
他的时间复杂度显然是O(#个数的四次方)最坏情况下全是#,即N的平方,那么就是O(N的八次方),N<=100,那么为10的16次方,显然是不行的,百分之百tle。

那我们思考几个点能确定一个正方形?

1.两个点确定一个正方形,然后判断其余两个点是否为“#”

2.三个点确定一个矩形,若矩形边平行于坐标轴,则只需要两个点

在这里插入图片描述
我们就去枚举A、C这两个点,都是有#的,然后直接算出B、D两点的坐标,去看一下他是不是#,如果是#,证明是正方形,如果不是#,则不是正方形,AC这条对角线不行。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=102;
char s[N][N]; 
int n;
/*
struct node{
	int x,y;
}dot[N*N];
*/
int x[N*N],y[N*N];
typedef pair<int,int> Point;
set<Point> pset;
int main()
{
	ios::sync_with_stdio(false);
	while(cin>>n){
		int k=0;
		pset.clear();
		for(int i=0;i<n;i++)
		{	
		scanf("%s",s[i]);
			for(int j=0;j<n;j++)
			{
				if(s[i][j]=='#'){
					x[k]=i+1;
					y[k]=j+1;
					//cout<<i<<" "<<j<<endl; 
					pset.insert(make_pair(x[k],y[k]));
					k++;
				}
			}
		}
		int cnt=0;//边长的平方 
		for(int i=0;i<k;i++)
		{
			for(int j=i+1;j<k;j++)
			{
				int mx=x[i]+x[j],dx=max(x[i],x[j])-min(x[i],x[j]);
				int my=y[i]+y[j],dy=max(y[i],y[j])-min(y[i],y[j]);
				if((mx+dy)&1||(my+dx)&1)	continue;
				int sg=((x[i]-x[j])*(y[i]-y[j])<0)?1:-1;
				if(pset.count(make_pair((mx+dy)/2,(my+sg*dx)/2))&&
				pset.count(make_pair((mx-dy)/2,(my-sg*dx)/2)))
				{
					int dis=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
					dis=dis/2;
					cnt=max(cnt,dis);
				}
			}
		}
		cout<<sqrt(cnt)<<endl; 
	}
	return 0;
 } 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值