1. 程式人生 > >Squares (統計內部正方形個數)

Squares (統計內部正方形個數)

Squares

A children's board game consists of a square array of dots that contains lines connecting some dots. One part of the game requires that the players count the number of squares that are formed by these lines. For example, in the figure shown below, there are 3 squares, 2 of size 1 and 1 of size 2 , so the total number of squares is 3. (The "size" of a square is the number of lines segments required to form a side.)

Your task is to write a program to count the number of all the possible squares.

Input 

The input represents a series of game boards. Each board consists of a description of a square array of n ^ 2 dots (where 2 <= n <= 1500) and some interconnecting horizontal and vertical lines. A record of a single board with n ^ 2 dots and m (m <= 300000 )interconnecting lines is formatted as follows: Line 1: "n" the number of dots in a single row or column. Line 2: "m" the number of interconnecting lines. Each of the next m lines are one of following two types: "H i j k" (1 <= i, j <= n, k >0, j + k <= n) indicates a horizontal line of length k from the dot in row i, column j to the dot in row i, column j + k. or "V i j k" (1 <= i, j <= n, k >0, i + k <= n) indicates a vertical line of length k from the dot in row i, column j to the dot in row i + k, column j. The end of input is indicated by end-of-file.

Output

For each record print only one integer, which is the number of squares.

Sample Input

4
9
H 1 1 1
H 1 3 1
H 2 1 3
H 3 2 1
H 4 2 2
V 1 1 1
V 1 2 3
V 2 3 1
V 1 4 3
4
9
H 1 1 1
H 1 3 1
H 2 1 3
H 3 2 1
H 4 2 2
V 1 1 1
V 1 2 3
V 2 3 1
V 1 4 3

Sample Output

3
3

思路:

思路很簡單,用兩個陣列存水平線和豎直線,然後先列舉正方形的邊長,然後對於每個邊長列舉方格內的所有頂點,對於每個頂點,向右列舉處於同一水平邊和對邊的點,向下列舉處於同一豎直邊和對邊的點,如果列舉過程中任何一個頂點未在對應陣列中有記錄,說明該點不存在連線,自然不可組成正方形,否則遍歷能正常結束,說明所有點都有連線,計數加1,輸出當前邊長的正方形數,程式碼如下: --------------------- 作者:ShannonNansen 原文:https://blog.csdn.net/ShannonNansen/article/details/42708157

看到這裡,想了下(開始的時候思路錯誤),

正方形的一個點,經過兩條邊。如果是四個頂點構成正方形,這四個頂點必然被標記大於等於兩次。

所以按著這個思路寫了程式:

//Squares ,統計有多少正方形(錯誤)
//dacao
//2018/10/22

#include<iostream>
#include<cstring>
using namespace std;

const int maxn=1500;
//const int maxm=300000;
int grid[maxn+1][maxn+1];


int main()
{
	int n,m;//n代表一行點的個數,m代表提供的邊數
	while(cin>>n>>m)
	{
		memset(grid,0,sizeof(grid));
		
		char c;
		int i,j,k;
		while(m--)//輸入 
		{ 
			cin>>c>>i>>j>>k;
			if(c=='H')//如果是正方形,頂點至少被兩條邊相交,標記必然大於等於2 
				for(int tmp=0;tmp<=k;tmp++)
					grid[i][j+tmp]++;
			else if(c=='V')
				for(int tmp=0;tmp<=k;tmp++)
					grid[i+tmp][j]++; 
		} 
		
		//列印檢查 
		for(i=0;i<=4;i++)
		{
			for(j=0;j<=4;j++)
				cout<<grid[i][j];
			cout<<endl;
		}
		
		
		int count=0;//統計正方形個數 
		int lenth;//正方形邊長 
		for(lenth=n-1;lenth>=1;lenth--)
		{
			for(i=1;i+lenth<=n;i++) 
			{
				for(j=1;j+lenth<=n;j++)
				{
					if(grid[i][j]>=2&&grid[i][j+lenth]>=2&&grid[i+lenth][j]>=2&&grid[i+lenth][j+lenth]>=2)
						count++;
				}
			}
		} 
		cout<<count<<endl;
	} 
	return 0; 
} 

提交之後報錯,就想啊想,發現:如果是四個頂點構成正方形,這四個頂點必然被標記大於等於兩次;

但是,四個頂點被標記大於等於兩次,即使length相同,也不一定構成正方形(自己想reason)。

所以,只好看看參考文章的程式碼,然後寫出了正確但超時的程式碼

(我的判斷條件是,四個點都要是H,V陣列中被標記過)

//- Squares  統計正方形個數
//dacao
//2010/10/22 
#include <iostream>
#include <cstring>
using namespace std;

const int maxn=1500; 
bool v[maxn+1][maxn+1],h[maxn+1][maxn+1];	//分別存豎直線和水平線
 
int main()
{
	int m,n;
	while(cin>>n>>m)
	{
		memset(v,0,sizeof(v));
		memset(h,0,sizeof(h));
		char c;
		int i,j,k;
		while(m--)
		{
			cin>>c>>i>>j>>k;
			if(c=='H')
				for(int tmp=0;tmp<=k;tmp++)
					h[i][j+tmp]=true;	
			else
				for(int tmp=0;tmp<=k;tmp++)
					v[i+tmp][j]=true;	
		}
		
		int count=0;
		for(int length=n-1;length>=1;length--)	//列舉邊長
		{
			for(int i=1;i+length<=n;i++)
				for(int j=1;j+length<=n;j++)
				{
					if(h[i][j]&&h[i][j+length]&&h[i+length][j]&&h[i+length][j+length]&&v[i][j]&&v[i][j+length]&&v[i+length][j]&&v[i+length][j+length])
					//四個點既在行陣列中,也在列陣列中
						count++; 
				}	
		}
		cout<<count<<endl;
	}
	return 0;
}

如果要改進超時,感覺應該從邊的儲存結構入手,但是不會。

參考文章: