CSP题目:建立回收站

题目背景:

开学了,可是校园里堆积了不少垃圾杂物。

热心的同学们纷纷自发前来清理,为学校注入正能量~

题目描述:

通过无人机航拍我们已经知晓了n处尚待清理的垃圾位置,其中第i (1≤i≤n)处的坐标为(xi,yi),保证所有的坐标均为整数。

我们希望在垃圾集中的地方建立些回收站。具体来说,对于一个位置(x,y)是否适合建立回收站,我们主要考虑以下几点:

  1. (x,y)必须是整数坐标,且该处存在垃圾;
  2. 上下左右四个邻居位置,即(x,y+1)、(x,y-1)、(x+1,y)和(x-1,y)处,必须全部存在垃圾;
  3. 进一步地,我们会对满足上述两个条件的选址进行评分,分数为不大于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;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值