CCF准备日记——2020.12.02
题目编号:202009-1
题目名称:称检测点查询
使用语言:Java(Eclipese)
题目描述:
我的代码:
import java.util.Scanner;
public class Main {
private int id;//编号1,2,3,4...
private int x;
private int y;
private double dis;//距离,开平方之后的结果
public Main() {
}
public Main(int _id,int _x,int _y,double _dis) {
this.id = _id;
this.x = _x;
this.y = _y;
this.dis = _dis;
}
public int getId() {
return this.id;
}
public void setId(int _id) {
this.id = _id;
}
public int getX() {
return this.x;
}
public void setX(int _x) {
this.x = _x;
}
public int getY() {
return this.y;
}
public void setY(int _y) {
this.y = _y;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);//键盘输入对象
int num = scanner.nextInt();
int px = scanner.nextInt();
int py = scanner.nextInt();
//System.out.println("监测点个数为" + num + "人的位置是(" + px + "," + py + ")");
Main[] point = new Main[num];//声明创建对象数组
int tx = 0;//临时变量x
int ty = 0;//临时变量y
double tdis = 0;//临时变量距离
for(int i=0;i<num;i++) {
tx = scanner.nextInt();
ty = scanner.nextInt();
tdis = Math.sqrt((px-tx)*(px-tx) + (py-ty)*(py-ty));//计算距离
point[i] = new Main(i+1,tx,ty,tdis);//针对对象数组中的每一个对象调用带参的构造函数
}
// for(int j=0;j<num;j++) {
// System.out.println("第"+point[j].id+"个监测点的位置是("+point[j].x+","+point[j].y+
// ")距离为"+point[j].dis); }
double mindis = point[0].dis;//初始化最小距离为第一个监测点的距离
int minid = point[0].id;//初始化最小id为第一个监测点的id
for(int k=0;k<3;k++) {
mindis = point[0].dis;//每次循环都要重新设置搜索的起点
minid = point[0].id;//每次循环都要重新设置搜索的起点
for(int m=0;m<num;m++) {
if((point[m].dis<mindis) || ((point[m].dis==mindis) && (point[m].id<minid))) {
//如果当前距离小于最小距离,或者是当前距离等于最小距离并且id更小的话更新mindis与minid
mindis = point[m].dis;
minid = point[m].id;
}
}
//选择完一个minid后要将其对应的距离设为无穷大(以9999代替),设为无穷大相当于将其从对象数组中删去(由于不知道怎么删去对象所以用此下策)
point[minid-1].dis=9999;
System.out.println(minid);
}
}
}
我的分析:
- 好久没有这么专注的写过代码了。发现自己的代码能力下降真的好多。这道题基本没有任何难度,不涉及任何算法或者是高级的函数调用,只需要建立好相应的数据结构、完成输入输出、进行简单的计算就可以。但我却用了1个小时的时间完成这道题,要知道正式考试五道题才一共4个小时。这次耽误时间主要在java的书写格式以及基本语句的使用上,我相信多做题就可以很快找回手感的。
- 首先要强调的是Java的书写格式以及官方提交要求,官方要求所提交的主类必须命名为Main,并且程序的唯一入口必须是Main主类的主函数。既然选择了Java编程语言,就要既看到优点又容忍缺点。优点在于Java较容易实现面向对象的思想因此很多题目思路会更简单并且可调用的包与函数更多,但缺点就在于Java有一些不得不考虑的东西比如构造函数等等。
- 有关Java的部分特性我们需要注意的是。属性一般我们用private来修饰,构造函数用public修饰没有返回值,一般都需要既实现无参的构造函数也实现带参的构造函数。由于我们很多操作都在主类的主函数中执行,因此好像可以直接使用私有属性,但加上getter与setter或许更好。
- 有关这道题目我的基本思路是:首先完成Main类的属性及方法搭建(这种情况下是单独生成一个类更好呢还是在Main类中实现细节更好呢?)。完成基本的键盘输入以及变量的定义声明,在生成每个对象的时候直接计算出其相对于用户之间的距离存储为属性这样就只需要查值即可。有关筛选距离最小的三个检测点的核心逻辑,我是用两层循环实现的,外层三次循环每次找到当前最小距离的监测点并输出,输出之后要把当前最小监测点的距离改为无穷大(这里以9999代替)。内部循环遍历对象数组中所有对象依次跟mindis与minid比较,筛选出当前最小距离的监测点。
- 需要注意有关java输入的具体实现。我们常用的方法是使用Scanner对象,并且官方提交系统也明确表示可以接受Scanner对象作为标准的输入。Scanner默认使用空格作为输入的分界符当然回车也可以作为分界符,因此题目常见的输入方式均可以用Scanner实现。
Scanner scanner = new Scanner(System.in);//键盘输入对象
int a = scanner.nextInt();
double b = scanner.nextDouble();
float c = scanner.nextFloat();
String d = scanner.nextLine();
- 既然选择使用Java参与考试那么就不得不使用好Java类与对象的面向对象特性。我们需要注意对象数组的使用方法,大体分为两个步骤。首先声明对象数组,然后可以在循环中对对象数组中的每个元素(实际上只是一个指针)调用构造函数生成一个对象。
Main[] point = new Main[num];//声明创建对象数组
for(int i=0;i<num;i++) {
tx = scanner.nextInt();
ty = scanner.nextInt();
tdis = Math.sqrt((px-tx)*(px-tx) + (py-ty)*(py-ty));//计算距离
point[i] = new Main(i+1,tx,ty,tdis);//针对对象数组中的每一个对象调用带参的构造函数
}
- 下面是有关本题目我的代码核心逻辑的分析。可以说是很差劲漏洞百出,一点都不高效简洁。首先是我使用了两层循环才将问题解决,并且内层循环每次都要完整遍历整个对象数组,实际上完全不同完全遍历但我又一时想不起删除元素简化逻辑的方法。并且还出了很多的问题,关键的语句就在于将当前选择的最小距离监测点的距离改为无穷大。首先是这句话的位置的放置需要深思熟虑,并不是进入内层循环的if内部才执行而是每次外层循环结束都需要执行(无论minid有没有改变)。另外一开始我使用的是99作为无穷大,结果简单的测试用例可以通过最终评分却只有10分。我忽略了题目要求中对于参数范围的限定,因此经过几次较大数据的实验我将最大值确定为9999。
标准答案: - 改进思路:首先将监测点单独拉出来成一个类Location类,Main类中只需要当作程序的唯一入口也就是存放主函数就够了。这样单独拉出来一个类就需要实现完整的getter与setter,具体方法是代码上右键-source-Generate getter and setter。这样整理后的代码思路更加清晰。
- 除此之外还有关键的比较排序部分。我们使用的是Arrays包中的sort函数,而sort函数需要自定义比较器Comparator,具体方法如代码所示。需要注意的是重写Comparator中的compare函数,返回值是int,当判断条件为前面大于后面时返回1,前面小于后面时返回-1(这一点格外注意,一开始我就输出完全相反了)。
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Comparator<Location> comparator =new Comparator <Location>(){
public int compare(Location l1,Location l2){
if(l1.getDis()!=l2.getDis()) {
if(l1.getDis()<l2.getDis())
return -1;
else
return 1;
}
else {
if(l1.getId()<l2.getId())
return -1;
else
return 1;
}
}
};
Scanner scanner = new Scanner(System.in);
int num = scanner.nextInt();
int px = scanner.nextInt();
int py = scanner.nextInt();
//System.out.println("监测点个数为" + num + "人的位置是(" + px + "," + py + ")");
Location[] loc = new Location[num];
int tx = 0;
int ty = 0;
double tdis = 0;
for(int i=0;i<num;i++) {
tx = scanner.nextInt();
ty = scanner.nextInt();
tdis = Math.sqrt((px-tx)*(px-tx) + (py-ty)*(py-ty));
loc[i] = new Location(i+1,tx,ty,tdis);
}
Arrays.sort(loc,comparator);
System.out.println(loc[0].getId());
System.out.println(loc[1].getId());
System.out.println(loc[2].getId());
}
}
class Location{
private int id;
private int x;
private int y;
private double dis;
public Location() {
}
public Location(int _id,int _x,int _y,double _dis) {
this.id = _id;
this.x = _x;
this.y = _y;
this.dis = _dis;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public double getDis() {
return dis;
}
public void setDis(double dis) {
this.dis = dis;
}
}