题目背景:
开学了,可是校园里堆积了不少垃圾杂物。
热心的同学们纷纷自发前来清理,为学校注入正能量~
题目描述:
通过无人机航拍我们已经知晓了n处尚待清理的垃圾位置,其中第i (1≤i≤n)处的坐标为(xi,yi),保证所有的坐标均为整数。
我们希望在垃圾集中的地方建立些回收站。具体来说,对于一个位置(x,y)是否适合建立回收站,我们主要考虑以下几点:
- (x,y)必须是整数坐标,且该处存在垃圾;
- 上下左右四个邻居位置,即(x,y+1)、(x,y-1)、(x+1,y)和(x-1,y)处,必须全部存在垃圾;
- 进一步地,我们会对满足上述两个条件的选址进行评分,分数为不大于4的自然数,表示在(x±1,y±1)四个对角位置中有几处存在垃圾。
现在,请你统计一下每种得分的选址个数。
输入格式:
从标准输入读入数据。
输入总共有n+1行。
第1行包含一个正整数n,表示已查明的垃圾点个数。
第1+i行(1≤i≤n)包含由一个空格分隔的两个整数xi和yi,表示第i处垃圾的坐标。
保证输入的n个坐标互不相同。
输出格式:
输出到标准输出。
输出共五行,每行一个整数,依次表示得分为0、1、2、3和4的回收站选址个数。
样例1输入:
7
1 2
2 1
0 0
1 1
1 0
2 0
0 1
样例1输出:
0
0
1
0
0
样例1解释:
如图所示,仅有(1,1)可选为回收站地址,评分为2。
样例2输入:
2
0 0
-100000 10
样例2输出:
0
0
0
0
0
样例2解释:
不存在可选地址。
样例3输入:
11
9 10
10 10
11 10
12 10
13 10
11 9
11 8
12 9
10 9
10 11
12 11
样例3输出:
0
2
1
0
0
样例3解释:
1分选址:(10,10)和(12,10);
2分选址:(11,9)。
提示:
本题中所涉及的坐标皆为整数,且保证输入的坐标两两不同。
(1) 算法思想与设计思路
用二维数组a[1000][2]来存储存在垃圾的位置坐标,其中x值和y值分别存入到a[i][0]和a[i][1],用数组c[5]来记录分数分别为0,1,2,3,4的坐标点的个数。
先按照先x后y的方式进行从小到大的排序,即先比较x值,若相同,按照y值的大小决定顺序,y值小在前。
接着对于从i=2(i=1时因为左边不存在坐标点,必然不符合条件)开始的每一个坐标,若坐标i-1满足x值==i的x值、y值==i的y值-1,且坐标i+1满足x值==i的x值、y值==i的y值+1,则说明i坐标的上下位置存在垃圾,i可能满足条件,否则不满足,i++。
然后对于满足上下位置存在垃圾的坐标点,进一步遍历其左边x值==(i的x值-1)的坐标点,比较y值,来判断是否存在左边有垃圾的坐标点,并在遍历的过程中顺便用score统计四角存在垃圾的坐标点的个数。若存在,leftTag标1,并同理来判断i的右边的坐标点是否存在垃圾;否则i++。
若右边也存在,满足条件,相应的分数的坐标点的个数加一
(2) 算法关键函数代码
(3)实现过程中遇到的问题与解决方法
在完成这段题目时,对于应该用怎样的结构去存储每个坐标点思考了较长时间。最后考虑到坐标点的数量不会很大,但坐标点的x值和y值可能会比较大,且可能为负数,另外还考虑到对于每个点来说,需要进行判断的点的x值只有x,x+1和x-1,基本相邻,所以可以直接用线性表(二维数组,分别用来存储x和y)然后排序的方法来统计。
(4)代码实现
#include<iostream>
using namespace std;
int main()
{
int n; //n表示已查明的垃圾点个数
cin >> n;
int i;
int a[10000][2], c[5] = { 0 }; //c[5]用来存储各分数的回收站选址个数
int x, y;
for (i = 0; i < n; i++)
{
cin >> a[i][0] >> a[i][1];
} //输入数据
int j,min,t;
for (i = 0; i < n-1; i++) //按照先x后y,进行选择排序
{
min = i;
for (j = i+1; j < n; j++)
{
if (a[j][0] < a[min][0])
{
min = j;
}
else if (a[j][0] == a[min][0])
{
if (a[j][1] < a[min][1])
min = j;
}
}
t = a[i][0]; a[i][0] = a[min][0]; a[min][0] = t;
t = a[i][1]; a[i][1] = a[min][1]; a[min][1] = t;
}
int u,leftTag=0,rightTag=0,score;
//从头遍历一遍,找出符合条件的坐标并计算得分
for (i = 1; i < n-1; i++)
{
score = 0;
x = a[i][0]; y = a[i][1];
if (a[i - 1][0] == x && (a[i - 1][1] == y-1) && (a[i + 1][0] == x && a[i + 1][1] == y+1))//上下存在垃圾
{
leftTag = 0; rightTag = 0;
for (u = i-2;u>=0&&a[u][0]==x-1; u--)
{
if (a[u][1] == y)
leftTag = 1; //左边存在垃圾,leftTag标记置1
if (a[u][1] == y + 1 || a[u][1] == y - 1) //顺便记录一下对角位置有垃圾的个数
score++;
}
if (leftTag) //如果左边存在垃圾,检查右边是否存在
{
for (u = i + 2; u < n && a[u][0] == x + 1; u++)
{
if (a[u][1] == y)
rightTag = 1; //右边存在垃圾,rightTag标记置为1
if (a[u][1] == y + 1 || a[u][1] == y - 1)
score++;
}
}
if (rightTag == 1) //如果右边也存在垃圾,则说明符合条件,对应的分数个数加1
c[score]++;
}
}
for (i = 0; i < 5; i++)
cout << c[i] << endl;
return 0;
}