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]数组(以行序为主?貌似是吧)这在数组使用时是一个容易忽视的点。
在解题过程中,要深挖数据背后隐藏的特性,抓住特性可以拓宽我们的做题思路,同时也可以帮助我们优化代码(◦˙▽˙◦)
来源:CSDN
作者:廿士
链接:https://blog.csdn.net/z_2_0_/article/details/104212288