P1387最大正方形(dfs搜索,加暴力,加前缀和,加dp四种方法。)

 暴力:

怎么暴力,我们要找到一个在用邻接矩阵中存储的图案中找到可访问点能找到的最大正方形,我们应该怎么去找呢?

首先,我们可以考虑枚举正方形的边长,以一个点为起始点,不断向右以及向下延申,如果这个边长能够符合条件,那么就记录并更新,否则继续从下一个点开始枚举。

看代码。

#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int g[N][N];
int ans;

bool pd(int x1, int x2, int y1, int y2) {
	for (int i = x1; i <= x2; i++) {
		for (int j = y1; j <= y2; j++) {
			if (g[i][j] == 0)
				return false;
		}
	}
	return true;
}

int main() {
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> g[i][j];
		}
	}
	int maxn = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (g[i][j]) {
				int ans = 1;
				int h = i + 1;
				int w = j + 1;
				while (pd(i, h, j, w)) {
					h++;
					w++;
					ans++;
				}
				maxn = max(ans, maxn);
			}
		}
	}
	cout << maxn << "\n";

	return 0;
}

搜索:

怎么进行搜索?我们要搜索一个图案中的正方形,其中最大的难点就是x和y要同步,我们怎么解决呢?就是让x和y同时起步,同时增加或减少,不符合条件就退出,那么问题来了,怎么才能实现这一方案呢?

我们遍历一个点,如果这个点能访问,那么就以这个点为起始点开始搜索,用xx,yy记录该点,同时向下方扩展,如果满足正方形,边长加一,继续扩展搜索。就这样。

#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int g[N][N];
bool st[N][N];
int ans;
int xx;
int yy;
int maxn;

int dfs(int x, int y) {
	for (int i = xx; i <= x; i++) {
		if (!g[i][y])
			return 0;
	}
	for (int i = yy; i <= y; i++) {
		if (!g[x][i])
			return 0;
	}
	ans++;
	dfs(x + 1, y + 1);
}

int main() {
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> g[i][j];
		}
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (g[i][j]) {
				xx = i;
				yy = j;
				ans = 0;
				dfs(i, j);
				maxn = max(ans, maxn);
			}
		}
	}
	cout << maxn << "\n";

	return 0;
}

除此之外,我们还可以怎么样进行呢,答案就是前缀和,遇到0,1这样的情况时我们当然可以用前缀和,或者记录其相对位置的办法来特殊处理,从而得到答案。

怎么特殊处理呢?因为不是0就是1所以我们得正方形可以怎么判断呢?答案就是看看她的面积,也就是看一看这一段区间内的前缀和是否符合条件。

#include<cstdio>
#include<algorithm>

using namespace std;

const int maxn=105;
const int maxm=105;

int n,m,ans;
int a[maxn][maxm],sum[maxn][maxm];


int main() {
	int size;
	scanf("%d%d",&n,&m);
	size=min(n,m);
	for(int i=1;i<=n;i++) 
		for(int j=1;j<=m;j++) {
			scanf("%d",&a[i][j]);
			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
		}
	for(int i=1;i<=n;i++) 
		for(int j=1;j<=m;j++) {
			for(int l=1;l<=size;l++) {
				int rx=i+l-1;
				int ry=j+l-1;
				if(rx>n || ry>m || sum[rx][ry]-sum[rx][j-1]-sum[i-1][ry]+sum[i-1][j-1]!=l*l) break;
				if(ans<l) ans=l;
			}
		}
	printf("%d",ans);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值