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

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

	需要求出在所有的组合中,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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值