枚举算法
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;
}