csp练题记录(C语言,编译器dev c++)201912-2回收站选址

csp练题记录(C语言,编译器dev c++)201912-2回收站选址

一、题目描述

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

二、思路分析

解这道题我觉得需要以下两个步骤:1、找出所有的备选地址,用sel[]数组来标识是否是备选地址(在初始代码中);2、对所有备选地址进行评分。
其中,备选地址要具备:它上、下、左,右四邻位都有垃圾;对它评分时,就是看它左上、左下、右上,右下四个对角线元素的有垃圾的个数,分值0~5分。
开始的时候,怎么存储坐标信息让我感觉一筹莫展:想用链表来存储,每一个节点存储了它的上下左右四邻位的信息,这样遍历一遍就可以得到所有的备选地址,但这样带来了一个新的问题:评分时考虑的是它对角线上的,就很麻烦,水平不够,自然是整得越简单越好,于是干脆设置一个二维数组,简单直接。
初始的代码能跑,但很粗糙、暴力:对每一个坐标都完整遍历一遍数组,这样找出它上下左右四邻位共有几处有垃圾,当计数值count为4时,说明它是备选位置。参阅博客和咨询dalao后有了改进思路。
第一次优化思路
邻位的两个元素是相互的,你是我的左,那么相对的,你就是我的右。同理,上下也有一样的性质,也就是说,不必像初始代码中那样每次都完整遍历一遍。因此找备选地址时,就有以下的思路:
(个人感觉有点像递归)遍历到第i个元素时,由于邻位的概念如上是相互的,所以只需找到在它后边和它有邻位关系的,(它和它之前有邻位关系的已经在遍历到之前那个元素时记录过了)。体现在代码中如下:

for(i=0;i<n;i++)
{
  for(j=i+1;j<n;j++)
  {
   if(||||||右侧有垃圾)
   {
    sel[i]++;
    sel[j]++;
   }
  }
}

这样,只要sel[]数组中元素值为4,就说明它是一个备选地址。

三、代码

初始代码:

#include<stdio.h>
int main()
{
 int n,i,j;
 long int loc[1000][2]; 
 int sel[1000]={0};
 int score[5]={0},count;
 scanf("%d",&n);
 for(i=0;i<n;i++)//读入坐标 
 {
  scanf("%ld %ld",&loc[i][0],&loc[i][1]);
 }
 //找出备选坐标位置
 for(i=0;i<n;i++)
 {
  count=0;
  for(j=0;j<n;j++)
  {
   if(loc[i][0]==loc[j][0]&&loc[i][1]==loc[j][1]+1//上侧有 
   ||loc[i][0]==loc[j][0]&&loc[i][1]==loc[j][1]-1//下侧有 
   ||loc[i][1]==loc[j][1]&&loc[i][0]==loc[j][0]+1//右侧有 
   ||loc[i][1]==loc[j][1]&&loc[i][0]==loc[j][0]-1)//左侧有 
   {
    count++;
    if(count==4)
    break;
   }
  }
  if(count==4)
  {
   sel[i]=1;
  }
    }
    //评分
 for(i=0;i<n;i++)
 {
  count=0;
  if(sel[i])
  {
   for(j=0;j<n;j++)
   {
    if((loc[i][0]==loc[j][0]+1&&loc[i][1]==loc[j][1]+1)//右上有 
    ||(loc[i][0]==loc[j][0]+1&&loc[i][1]==loc[j][1]-1)//右下有 
    ||(loc[i][0]==loc[j][0]-1&&loc[i][1]==loc[j][1]+1)//左上有 
    ||(loc[i][0]==loc[j][0]-1&&loc[i][1]==loc[j][1]-1))//左下有
    {
     count++;
    } 
   }
   score[count]++;
  }
 } 
 for(i=0;i<5;i++)
 {
  printf("%d\n",score[i]);
 }
 return 0;
}

第一次优化后代码:

#include<stdio.h>
int main()
{
 int n,i,j;
 long int loc[1000][2]; 
 bool sel[1000]={0};
 int score[5]={0},count;
 scanf("%d",&n);
 for(i=0;i<n;i++)//读入坐标 
 {
  scanf("%ld %ld",&loc[i][0],&loc[i][1]);
 }
 //找出备选坐标位置
 for(i=0;i<n;i++)
 {
  for(j=i+1;j<n;j++)
  {
   if(loc[i][0]==loc[j][0]&&loc[i][1]==loc[j][1]+1//上侧有 
   ||loc[i][0]==loc[j][0]&&loc[i][1]==loc[j][1]-1//下侧有 
   ||loc[i][1]==loc[j][1]&&loc[i][0]==loc[j][0]+1//右侧有 
   ||loc[i][1]==loc[j][1]&&loc[i][0]==loc[j][0]-1)//左侧有 
   {
    sel[i]++;
    sel[j]++;
   }
  }
    }
    //评分
 for(i=0;i<n;i++)
 {
  count=0;
  if(sel[i]==4)
  {
   for(j=0;j<n;j++)
   {
    if((loc[i][0]==loc[j][0]+1&&loc[i][1]==loc[j][1]+1)//右上有 
    ||(loc[i][0]==loc[j][0]+1&&loc[i][1]==loc[j][1]-1)//右下有 
    ||(loc[i][0]==loc[j][0]-1&&loc[i][1]==loc[j][1]+1)//左上有 
    ||(loc[i][0]==loc[j][0]-1&&loc[i][1]==loc[j][1]-1))//左下有
    {
     count++;
    } 
   }
   score[count]++;
  }
 } 
 for(i=0;i<5;i++)
 {
  printf("%d\n",score[i]);
 }
 return 0;
}

四、反思总结

打代码时,又犯了一个白痴型错误,scanf函数格式马虎了,忘打%,无语了,很慌,之前欠下的学习债不知道能不能还上(。•́︿•̀。)。
不过貌似csp前两题暴力粗糙点能解出来。。。尤其是遇到数据存储拿捏不好用什么数据结构的时候,直接上数组就好了。二维数组可以看作两个一维数组,a[i][j]就可以视为j个a[i]数组(以行序为主?貌似是吧)这在数组使用时是一个容易忽视的点。
在解题过程中,要深挖数据背后隐藏的特性,抓住特性可以拓宽我们的做题思路,同时也可以帮助我们优化代码(◦˙▽˙◦)

发布了4 篇原创文章 · 获赞 2 · 访问量 211

猜你喜欢

转载自blog.csdn.net/z_2_0_/article/details/104212288