题意:
有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)。
思路:
读入的时候,先对每个点是否存在先左或向下的边做标记。然后统计从这点开始向左和向下的最大边长。如果要判断是否存在以(i,j)为左上顶点的边长为len的正方形,只需要判断以(i,j)为起点向左和向下的最大边长,以(i+len,j)为起点的向左的最大边长,以(i,j+len)为起点的向下的最大边长是否都满足>=len。
对于n*n个点最大的正方形边长是n-1。
#include <stdio.h>
#include <string.h>
#define maxn 11
struct POINT {
int R;//表示该点向右的最大边长
int C;//表示该点向下的最大边长
}a[maxn][maxn];
int n, m, r, c, ans[maxn], cases=0, count, first=1;
char s[2];
void clear()
{
for (int i = 0;i <= maxn;i++)
for (int j = 0;j <= maxn;j++)
{
a[i][j].R = 0;
a[i][j].C = 0;
}
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
while (~scanf("%d%d", &n,&m))
{
memset(ans, 0, sizeof(ans));
clear();
for (int i = 1;i <= m;i++)
{
scanf("%s%d%d", s, &r, &c);
if (s[0] == 'H') a[r][c].R= 1;
else a[c][r].C = 1;//注意下标的变化
}
for (int i = 1;i <= n;i++)
{
for (int j = 1;j <= n;j++)
{
if (a[i][j].R)//如果该点先左有边
{
for (int k = j + 1;k <= n;k++)//从该点一直向左统计最大边长
if (a[i][k].R) a[i][j].R++;
else break;//遇到连接中断退出
}
if (a[i][j].C)
{
for (int k = i + 1;k <= n;k++)
if (a[k][j].C) a[i][j].C++;
else break;
}
}
}
/*
for (int i = 1;i <= n;i++)
{
for (int j = 1;j <= n;j++)
printf("(%d,%d) ", a[i][j].R, a[i][j].C);
printf("\n");
}
*/
for (int len = 1;len < n;len++)//最大可能边长是n-1
{
for (int i = 1;i <= n - len;i++)
{
for (int j = 1;j <= n - len;j++)
if (a[i][j].R >= len&&a[i][j].C >= len&&a[i + len][j].R >= len&&a[i][j + len].C >= len)
ans[len]++;//ans[len]表示以len为边长的正方形数量
}
}
if (first) first = 0;
else printf("\n**********************************\n\n");
printf("Problem #%d\n\n", ++cases);
count = 0;
for (int i = 1;i < n;i++)
{
if (ans[i])
{
count++;
printf("%d square (s) of size %d\n", ans[i], i);
}
}
if (!count) //不存在正方形
printf("No completed squares can be found.\n");
}
return 0;
}