【JAVA】

/*已知平面上若干个点的坐标。

需要求出在所有的组合中,4个点间平均距离的最小值(四舍五入,保留2位小数)。

比如有4个点:a,b,c,d, 则平均距离是指:ab, ac, ad, bc, bd, cd 这6个距离的平均值。

每个点的坐标表示为:横坐标,纵坐标

坐标的取值范围是:1~1000

所有点的坐标记录在in.txt中,请读入该文件,然后计算。

注意:我们测试您的程序的时候,in.txt 可能会很大,比如包含上万条记录。

举例:
如果,in.txt 内的值为:

10,10
20,20
80,50
10,20
20,10

则程序应该输出:
11.38

编程,读入in.txt文件,计算并输出4个点平均距离的最小值。


要求考生把所有函数写在一个文件中。调试好后,存入与考生文件夹下对应题号的“解答.txt”中即可。
相关的工程文件不要拷入。
不能使用诸如绘图、中断调用等硬件相关或操作系统相关的API。
*/

以下代码是网上好友的,我只是在代码里添加注释来理解它,以供大家一起学习。



import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Vector;
/**
 *
 * @author 网友
 *
 */
//定义点
class PP {
    public int x;
    public int y;
    public String toString() {
        return x + "," + y;
    }
    public PP(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
//定义矩形
class RR {
    double x1;
    double x2;
    double y1;
    double y2;
    public RR() {
    }
    public RR(double x1, double y1, double x2, double y2) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
    }
    //判断点是不是在矩形内
    boolean isIn(PP p) {
        return (x1 < p.x && p.x < x2 && y1 < p.y && p.y < y2);
    }
}
public class Main {
                
    //参数:点的集合、矩形面积
    public static double f(List<PP> lis, RR r) {
        //判断如果点数小于4则不能计算,不符合要求,返回一个很大的数
        if (lis.size() < 4)
            return 10000.0;
        //递归的关键步!如果点数小于13,则进行如下计算
        if (lis.size() < 13) {
            double min = 10000;
            for (int i = 0; i < lis.size(); i++)
                for (int j = i + 1; j < lis.size(); j++)
                    for (int k = j + 1; k < lis.size(); k++)
                        for (int m = k + 1; m < lis.size(); m++) {
                            double d = distance(lis.get(i), lis.get(j),
                                    lis.get(k), lis.get(m));
                            if (d < min)
                                min = d;
                        }
            return min;
        }
                    
        //缩小边界
                    
        double x1a = r.x1;
        double x2a = r.x2;
        double y1a = r.y1;
        double y2a = r.y2;
                    
        for (int i = 0; i < lis.size(); i++) {
            PP p = lis.get(i);
            if (p.x < x1a)
                x1a = p.x;
            if (p.x > x2a)
                x2a = p.x;
            if (p.y < y1a)
                y1a = p.y;
            if (p.y > y2a)
                y2a = p.y;
            System.out.println("1,"+x1a+":"+x2a+":"+y1a+":"+y2a);
        }
        System.out.println(x1a+":"+x2a+":"+y1a+":"+y2a);
                
        r.x1 = x1a;
        r.x2 = x2a;
        r.y1 = y1a;
        r.y2 = y2a;
        //创建四个矩形区域
        RR r1 = new RR();
        RR r2 = new RR();
        RR r3 = new RR();
        RR r4 = new RR();
        r1.x1 = r.x1;
        r1.y1 = r.y1;
        r1.x2 = r.x1 * 0.25 + r.x2 * 0.75;
        r1.y2 = r.y1 * 0.25 + r.y2 * 0.75;
        r2.x1 = r.x1 * 0.75 + r.x2 * 0.25;
        r2.y1 = r.y1 * 0.75 + r.y2 * 0.25;
        r2.x2 = r.x2;
        r2.y2 = r.y2;
        r3.x1 = r.x1;
        r3.y1 = r.y1 * 0.75 + r.y2 * 0.25;
        r3.x2 = r.x1 * 0.25 + r.x2 * 0.75;
        r3.y2 = r.y2;
        r4.x1 = r.x1 * 0.75 + r.x2 * 0.25;
        r4.y1 = r.y1;
        r4.x2 = r.x2;
        r4.y2 = r.y1 * 0.25 + r.y2 * 0.75;
        List<PP> t1 = new Vector<PP>();
        List<PP> t2 = new Vector<PP>();
        List<PP> t3 = new Vector<PP>();
        List<PP> t4 = new Vector<PP>();
        //将集合点规划在小的矩形区域里
        for (int i = 0; i < lis.size(); i++) {
            PP p = lis.get(i);
            if (r1.isIn(p))
                t1.add(p);
            if (r2.isIn(p))
                t2.add(p);
            if (r3.isIn(p))
                t3.add(p);
            if (r4.isIn(p))
                t4.add(p);
        }
        //关键!递归
        double d1 = f(t1, r1);
        double d2 = f(t2, r2);
        double d3 = f(t3, r3);
        double d4 = f(t4, r4);
        //比较得出最小距离
        double d = d1;
        if (d2 < d)
            d = d2;
        if (d3 < d)
            d = d3;
        if (d4 < d)
            d = d4;
        return d;
    }
    //点与点之间的距离
    public static double distance(PP a1, PP b1) {
        double dx = Math.abs(a1.x - b1.x);
        double dy = Math.abs(a1.y - b1.y);
        return Math.sqrt(dx * dx + dy * dy);
    }
    //四个点之间的平均距离
    public static double distance(PP a, PP b, PP c, PP d) {
        double dis = (distance(a, b) + distance(a, c) + distance(a, d)
                + distance(b, c) + distance(b, d) + distance(c, d)) / 6.0;
        return dis;
    }
    //读取点的数据
    public static List<PP> readPoints(String fname) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(
                new FileInputStream(fname)));
        List<PP> lis = new Vector<PP>();
        for (;;) {
            String s = br.readLine();
            if (s == null)
                break;
            String[] ss = s.split(",");
            PP e = new PP(0, 0);
            e.x = Integer.parseInt(ss[0]);
            e.y = Integer.parseInt(ss[1]);
            lis.add(e);
        }
        br.close();
        return lis;
    }
    public static void main(String[] args) throws Exception {
        //获取点数据的集合
        List<PP> lis = readPoints("in.txt");
        //计算四个点之间的最小平均距离
        double x = f(lis, new RR(0, 0, 1000, 1000));
        System.out.printf("%.2f", x);
    }
}


测试数据 in.txt

10,10

20,20

80,50

10,20

20,10

30,30

40,40

50,50

60,60

70,70

80,80

90,90

100,200