题目:有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;
}
有错误的请大家指出。