数数正方形(ACM/ICPC World Finals)

题目:有n行n列(2<=n<=9)的小黑点,还有m条线段连接其中的一些黑点,统计这些线段连成了多少个正方形(每种边长分别统计)

从上到下编号为1~n,从上到下编号为1~n。边用 H(i,j)V(i,j)表示, 分别表示 (i,j)-(i,j+1)和(i,j)-(i+1,j)。如图所示最左边的线段用V(1,1)表示。图中包含两个边长为1的正方形和一个边长为2的正方形。

思路:用边长为 len(1,2,3,4.....,n-1)的正方形分别放进带边的小黑点,如果放进后能恰好把图中的4条边覆盖,则这是一个正方形,如果没覆盖够4条边,则表示没有连成正方形。

如何判断放进边长为len的正方形后能覆盖多少条边呢? 我们可以试试按正方形的边走一圈,如果能走过4条边,则就证明能覆盖4条边。

我们首先用边长len的正方形竖着的边 进行遍历,

例如

len=1:

如果遍历到

V(i,j),就检测

V(i,j+1),

H(i,j),

H(i+1,j)。

len=2:

如果遍历到

V(i,j),就检测

V(i+1,j)

V(i,j+2)

V(i+1,j+1)

H(i,j)

H(i,j+1)

H(i+2,j)

H(i+2,j+1)

len=k:

如果遍历到

V(i+0,j),就检测

.....

V(i+(k-1),j)

V(i,j+k)

.....

V(i+(k-1),j+k)

H(i,j)

.....

H(i,j+(k-1))

H(i+k,j+0)

.....

H(i+k,j+(k-1))

所以判断是否为正方形的代码为:

bool judge(int a, int b, int len) {
	int i;
	for (i = 0; i < len; i++)
		if (V[a + i][b] == 0 || V[a + i][b + len] == 0 || H[a][b + i] == 0 || H[a + len][b + i] == 0)
			return 0;
	return 1;
}

遍历的时候,并不需要把每一条 竖着的边 都遍历,我们只需要遍历正方形左边的 “竖着的边”,如果正方形左边存在的话,接下来再遍历正方形的其他边

代码例:

#include<iostream>
using namespace std;

int H[10][10];//记录纵边
int V[10][10];//记录横边

bool judge(int a, int b, int len) { //判断正方形是否存在
	int i;
	for (i = 0; i < len; i++)
		if (V[a + i][b] == 0 || V[a + i][b + len] == 0 || H[a][b + i] == 0 || H[a + len][b + i] == 0)
			return 0;
	return 1;
}

int main() {
	memset(H, 0, sizeof(H));
	memset(V, 0, sizeof(V));

	int Hcount, Vcount;
	cin >> Hcount;  //纵边数量
	cin >> Vcount; //横边数量

	int a, b, i;
	for (i = 0; i < Hcount; i++) {
		cin >> a >> b;
		H[a][b] = 1;
	}
	for (i = 0; i < Vcount; i++) {
		cin >> a >> b;
		V[a][b] = 1;
	}
	int len, n, sum;
	cin >> n;
	len = 1;
	sum = 0;
	while (len < n) {
		int i, j, k;
		for (i = 1; i <= n - len; i++) {
			for (j = 1; j <= n - len; j++) {
				for (k = 0; k < len; k++) {
					if (V[i + k][j] == 0)break;
				}
				if (k == len)//如果正方形左边的“竖着的边”存在,则继续判断其他边
					if (judge(i, j, len))
						sum++;
			}
		}
		len++;
	}

	cout << sum;
	return 0;
}

有错误的请大家指出。

猜你喜欢

转载自blog.csdn.net/qq742762377/article/details/81452671