UVa 201 Squares

本文介绍了一种高效算法来解决在一个由水平和垂直边构成的网格图中寻找所有可能大小及位置不同的正方形的问题。该算法通过预处理水平和垂直边的数量,使用三维数组存储这些信息,并利用这些信息来在O(n^3)的时间复杂度内查找所有符合条件的正方形。
摘要由CSDN通过智能技术生成

题意:

给出这样一个图,求一共有多少个大小不同或位置不同的正方形。

分析:

这种题一看就有思路,最开始的想法就是枚举正方形的位置,需要二重循环,枚举边长一重循环,判断是否为正方形又需要一重循环,复杂度为O(n4),对于n≤9来说,这个复杂度可以接受。

可以像预处理前缀和那样,用O(1)的时间判断是否为正方形,这样总的复杂度就优化到O(n3)。

这个方法转自这里

We can think that vertical or horizontal lines are edges between two adjecent point. After that we can take a three dimensional array (say a [N][N][2]) to store the count of horizontal(a[i][j][0]) edges and vertical(a[i][j][1]) edges. a[i][j][0] contains number of horizontal edges at row i upto coloumn j. and a[i][j][1] contains number of vertical edges at coloumn j upto row i. Next you use a O(n^2) loop to find a square. a square of size 1 is found if there is an edge from (i,j) to (i,j+1) and (i,j+1) to (i+1,j+1) and (i,j) to (i+1,j) and (i+1,j) to (i+1,j+1) we can get this just by subtracting values calculated above.

举个例子,a[i][j][0]表示在第i行上,从第一列到第j列水平边数,如果a[i][j+l][0] - a[i][j][0],说明点(i, j)到(i, j+l)有一条长为l的水平线段。

我还被输入坑了,注意VH后面,哪个数代表行,哪个数代表列。

 1 #include <cstdio>
 2 #include <cstring>
 3 
 4 const int maxn = 10;
 5 bool G[2][maxn][maxn];
 6 int a[2][maxn][maxn], cnt[maxn];
 7 
 8 int main()
 9 {
10     //freopen("in.txt", "r", stdin);
11     int n, m, kase = 0;
12     while(scanf("%d", &n) == 1 && n)
13     {
14         memset(G, false, sizeof(G));
15         memset(a, 0, sizeof(a));
16         memset(cnt, 0, sizeof(cnt));
17         scanf("%d", &m);
18         getchar();
19         for(int k = 0; k < m; ++k)
20         {
21             char c;
22             int i, j;
23             scanf("%c %d %d", &c, &i, &j);
24             getchar();
25             if(c == 'H') G[0][i][j+1] = true;
26             else G[1][j+1][i] = true;
27         }
28         for(int i = 1; i <= n; ++i)
29             for(int j = 1; j <= n; ++j)
30             {
31                 a[0][i][j] = a[0][i][j-1] + G[0][i][j];
32                 a[1][i][j] = a[1][i-1][j] + G[1][i][j];
33             }
34 
35         for(int i = 1; i < n; ++i)
36             for(int j = 1; j < n; ++j)  //枚举正方形的左上角
37                 for(int l = 1; i+l<=n && j+l<=n; ++l)   //枚举正方形的边长
38                     if(a[0][i][j+l]-a[0][i][j] == l && a[0][i+l][j+l]-a[0][i+l][j] == l
39                        && a[1][i+l][j]-a[1][i][j] == l && a[1][i+l][j+l]-a[1][i][j+l] == l)
40                         cnt[l]++;
41 
42         if(kase) printf("\n**********************************\n\n");
43         printf("Problem #%d\n\n", ++kase);
44         bool flag = false;
45         for(int i = 1; i <= n; ++i) if(cnt[i])
46         {
47             printf("%d square (s) of size %d\n", cnt[i], i);
48             flag = true;
49         }
50         if(!flag) puts("No completed squares can be found.");
51     }
52 
53     return 0;
54 }
代码君

 

转载于:https://www.cnblogs.com/AOQNRMGYXLMV/p/4206130.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值