/*
* 已知平面上若干个点的坐标。
需要求出在所有的组合中,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
*/
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Vector;
// 代表一个点
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 y1;
double x2;
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 T07 {
public static double f(List<PP> lst, RR r) {
// lst:当前要处理的点,r:当前区域
if (lst.size() < 4)
return 10000; // 代表很远
if (lst.size() < 13) {
// 测试中所有13中选4的组合
double min = 10000;
for (int i = 0; i < lst.size(); i++)
for (int j = i + 1; j < lst.size(); j++)
for (int k = j + 1; k < lst.size(); k++)
for (int m = k + 1; m < lst.size(); m++) {
double d = distance(lst.get(i), lst.get(j),
lst.get(k), lst.get(m));
if (d < min)
min = d;
}
return min;
}
// 缩小边界
double x1a = r.x2;
double x2a = r.x1;
double y1a = r.y2;
double y2a = r.y1;
for (int i = 0; i < lst.size(); i++) {
PP p = lst.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;
}
r.x1 = x1a;
r.x2 = x2a;
r.y1 = y1a;
r.y2 = y2a;
// 拆分lst 为4块,重叠4个区域
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; // 0.75*(x2-x1) + x1
r1.y2 = r.y1 * 0.25 + r.y2 * 0.75;
r2.x1 = r.x1 * 0.75 + r.x2 * 0.25; // 0.25*(x2-x1) + x1
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>();
// isIn(p)判断是否在该矩形中
for (int i = 0; i < lst.size(); i++) {
PP p = lst.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;
}
// 计算 4个点间平均距离
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 double distance(PP a, PP b){
double dx = a.x - b.x;
double dy = a.y - b.y;
return Math.sqrt(dx*dx + dy*dy);
}
// 读入文件,填入List中
public static List<PP> readPoints(String fname)throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fname)));
List<PP> lst = new Vector<PP>();
for(;;){
String s = br.readLine();
if(s==null) break;
String[] ss = s.split(",");
PP a = new PP(0,0);
a.x = Integer.parseInt(ss[0]);
a.y = Integer.parseInt(ss[1]);
lst.add(a);
}
br.close();
return lst;
}
public static void main(String[] args) throws Exception {
List<PP> lst = readPoints("in.txt");
double x = f(lst, new RR(0, 0, 1000, 1000));
System.out.printf("%.2f",x);
}
}
运行结果:
11.38