AOJ1213 Heavenly Jewels

問題リンク Heavenly Jewels

  • 概要

大きさ、[0, 10000]*[0, 10000]の島にIC, PC, ACMの3人の男の家がある。島のある座標に天から宝石がおとされ、男たちは同時に同じ速度で宝石に向かって一直線に向かい、最初に宝石にたどり着いたものが宝石を手に入れる。同時にたどり着いた場合はIC > PC > ACMの優先順序で宝石を手に入れる。
宝石は島の全ての場所に等確率で落とされるものとしたとき、ICが宝石を手に入れられることができる確率を求めよ。

  • 解法

ストレートなボロノイ図の問題になります。ICの持つ領域の面積の割合がそのまま答えになります。
ボロノイ図は各点の垂直2等分線によって領域を分割していけば求まることができます。

  • ソース
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

//Heavenly Jewels
public class AOJ1213 {

	double EPS = 1e-8;
	double norm(Point p) {
		return Math.hypot(p.x, p.y);
	}
	double inp(Point p1, Point p2) {
		return p1.x*p2.x + p1.y*p2.y;
	}
	double extp(Point p1, Point p2) {
		return p1.x*p2.y - p2.x*p1.y;
	}
	Point sub(Point p1, Point p2) {
		return new Point(p1.x-p2.x, p1.y-p2.y);
	}
	int ccw(Point a, Point b, Point c) {
		Point p = sub(b, a);
		Point q = sub(c, a);
		if(extp(p, q) > EPS) return 1;		// counter clockwise
		if(extp(p, q) < -EPS)return -1;		// clockwise
		if(inp(p, q) < -EPS) return 2;		// c--a--b on line
		if(Math.abs(norm(p) - norm(q)) < EPS) return -2;	// a--b--c on line
		return 0;				// a--c--b(or a--c=b) on line 
	}
	Point crosspoint(Line l, Line m) {
		if(isParallel(l, m)){
			throw new IllegalArgumentException("parallel");
		}
		double A = extp(sub(l.t, l.s), sub(m.t, m.s));
		double B = extp(sub(l.t, l.s), sub(l.t, m.s));
		if (Math.abs(A) < EPS && Math.abs(B) < EPS) return m.s; // same line
		if (Math.abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
		Point tp = sub(m.t, m.s);
		return new Point(m.s.x + B/A*tp.x, m.s.y + B/A*tp.y);
	}
	boolean isParallel(Line l, Line m){
		Point a = new Point(l.t.x - l.s.x, l.t.y - l.s.y);
		Point b = new Point(m.t.x - m.s.x, m.t.y - m.s.y);
		if(Math.abs(Math.abs((a.x*b.x + a.y*b.y)/(Math.hypot(a.x, a.y)*Math.hypot(b.x, b.y)) - 1)) < EPS){
			return true;
		}
		return false;
	}

	double area(Point[] p) {
		double s = 0;
		for(int i=0; i<p.length; i++) {
			int j = (i+1)%p.length;
			s += extp(p[i], p[j]);
		}
		s /= 2;
		return Math.abs(s);
	}
	Point[] convexCut(Point[] p, Line l) {
		List<Point> q = new ArrayList<Point>();
		for (int i = 0; i < p.length; ++i) {
			Point a= p[i], b = p[(i+1)%p.length];
			if (ccw(l.s, l.t, a) != -1) q.add(a);
			if (ccw(l.s, l.t, a)*ccw(l.s, l.t, b) < 0)
				q.add(crosspoint(new Line(a, b), l));
		}
		return q.toArray(new Point[q.size()]);
	}

	class Point {
		double x;
		double y;
		public Point(double x_, double y_) {
			x = x_; y=y_;
		}
	}
	class Line {
		Point s,t;
		public Line(Point s_, Point t_) {
			s = s_; t = t_;
		}
	}

	void run(){
		Scanner sc = new Scanner(System.in);
		int T = 1;
		for(;;){
			int x1 = sc.nextInt(), y1 = sc.nextInt(), x2 = sc.nextInt(), y2 = sc.nextInt(), x3 = sc.nextInt(), y3 = sc.nextInt();
			if((x1|y1|x2|y2|x3|y3)==0)break;
			Point[] p = new Point[4];
			p[0] = new Point(0, 0);
			p[1] = new Point(10000, 0);
			p[2] = new Point(10000, 10000);
			p[3] = new Point(0, 10000);
			Point ic = new Point(x1, y1);
			Point pc = new Point(x2, y2);
			Point ac = new Point(x3, y3);
			Point mid = new Point((x1+x2)/2.0, (y1+y2)/2.0);
			Point sub = sub(pc, ic);
			Point r = new Point(mid.x-sub.y, mid.y+sub.x);
			p = convexCut(p, new Line(mid, r));
			mid = new Point((x1+x3)/2.0, (y1+y3)/2.0);
			sub = sub(ac, ic);
			r = new Point(mid.x-sub.y, mid.y+sub.x);
			p = convexCut(p, new Line(mid, r));
			double a = area(p);
			System.out.printf("%d %.5f\n", T++, a/(100000000));
		}
	}

	public static void main(String[] args) {
		new AOJ1213().run();
	}
}