试题C:直线

文章介绍了在蓝桥杯大赛中处理直线问题的两种方法。一是通过自定义排序的集合来解决double类型的比较问题,二是利用重写equals和hashCode方法将数据存入Map避免重复。关键在于处理浮点数近似相等的情况以及避免集合中的数据覆盖。
摘要由CSDN通过智能技术生成

解析:

一、分析

        分数10分,没有考什么算法知识,暴力求解。

面临的问题主要有:

        ①当x1=x2时,单独分析;

        ②斜率k为double型。怎么比较,不可以直接使用等号比较

        ③不能使用set结构,因为当set的key值相同value不同时会直接覆盖前面的记录,而本题却可能出现k相同,b不同的情况。

        ④可以通过重写equals函数和hasCode函数来使double值之差小于10^{-8}的对象在比较时为同一对象。

二、思路

1、方法一

        通过家所有的k和b加入一个集合中,然后按照制定的规则排序,当k和b的差都小于10^{-8}时才看做相等。

注意事项:

  • 分母不为0
  • 集合的自定义排序
  • double类型的比较是通过差值不大于某一既定值决定的
  • res初始值为1是因为第一个值
import java.util.*;

//第十二届蓝桥杯大赛软件赛省赛-Java研究生组
//试题C:直线(10分)
//OJ:http://oj.zhtwinkle.cn/d/lanqiao_zhenti/p/261

public class ExaminationC {
    public static void main(String[] args) {
        int row=20,column=21;
        List<Bean> list = new ArrayList<>();

        double k=0,b=0;
        for (int x1 = 0; x1 < row; x1++) {
            for (int y1 = 0; y1 < column; y1++) {
                for (int x2 = 0; x2 < row; x2++) {
                    for (int y2 = 0; y2 < column; y2++) {
                        if(x1!=x2){
                            k = 1.0*(y2-y1)/(x2-x1);
                            b = y2 - k*x2;
                            list.add(new Bean(k,b));
                        }
                    }
                }
            }
        }
        Collections.sort(list, new Comparator<Bean>() {
            @Override
            public int compare(Bean o1, Bean o2) {
                if (o1.k==o2.k) {
                    if(o1.b>o2.b)
                        return 1;
                    return -1;
                }
                if (o1.k>o2.k) {
                    return 1;
                }
                return -1;
            }
        });

        int res = 1;//第一个直接算上
        for (int i = 0; i < list.size()-1; i++) {
            //浮点数的比较不能直接用等于号
            if(Math.abs(list.get(i).k-list.get(i+1).k)>1e-8||Math.abs(list.get(i).b-list.get(i+1).b)>1e-8){
                res++;
            }
        }
        System.out.println(res+row);//每一列都没有算上,所以最后直接加上

    }
}

class Bean{
    double k;
    double b;

    public Bean(double k, double b) {
        this.k = k;
        this.b = b;
    }
}

2、方法二

重写equals和hasCode函数,将k和b封装,加入map集合中。

import java.util.*;

public class ExaminationC_2 {
    public static void main(String[] args) {
        int row=20,column=21;
        List<Bean> list = new ArrayList<>();
        Map map = new HashMap();

        double k=0,b=0;
        for (int x1 = 0; x1 < row; x1++) {
            for (int y1 = 0; y1 < column; y1++) {
                for (int x2 = 0; x2 < row; x2++) {
                    for (int y2 = 0; y2 < column; y2++) {
                        if(x1!=x2){
                            k = 1.0*(y2-y1)/(x2-x1);
                            b = y2 - k*x2;
                            map.put(new Bean_2(k,b),1);
                        }
                    }
                }
            }
        }
        System.out.println(map.size()+row);


    }
}

class Bean_2{
    double k;
    double b;

    public Bean_2(double k, double b) {
        this.k = k;
        this.b = b;
    }

    @Override
    public boolean equals(Object obj) {
        Bean_2 b = (Bean_2) obj;
        if(Math.abs(this.k-b.k)<1e-8&&Math.abs(this.b-b.b)<1e-8)
            return true;
        return false;
    }

    @Override
    public int hashCode() {
        int res = 17;
        //错误的原因在这:因为k和b不是绝对相等的,所以哈希值不等
        res = 31*res+(int)(k+0.5);
        res = 31*res+(int)(b+0.5);
        return res;
    }
}

参考材料

[1]「蓝桥杯」直线(Java)_直线蓝桥杯_小成同学_的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值