算法竞赛入门经典 8.3.3 巨人与鬼

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;

//比较器
class ModelComparator implements Comparator<Model> {
	Model m;

	ModelComparator(Model m) {
		this.m = m;
	}

	@Override
	public int compare(Model m1, Model m2) {
		int dx1 = m1.x - m.x;
		int dx2 = m2.x - m.x;
		int dy1 = m1.y - m.y;
		int dy2 = m2.y - m.y;
		double k1 = 0.0, k2;
		if (dx1 == 0)
			k1 = Double.MAX_VALUE;
		if (dx2 == 0)
			k2 = Double.MAX_VALUE;
		else {
			k1 = dy1 * 1.0 / dx1;
			k2 = dy2 * 1.0 / dx2;
		}
		if (k1 * k2 < 0) {// 斜率一正一负 负的大于正的
			if (k1 < k2)// k1 为负
				return 1;
			else
				return -1;
		} else {// 同号
			if (k1 < k2)
				return -1;
			else
				return 1;
		}
	}
}

class Model {
	int c; // 类别 0:巨人 1: 鬼
	int x; // 坐标
	int y; // 坐标

	public Model(int c, int x, int y) {
		super();
		this.c = c;
		this.x = x;
		this.y = y;
	}
}

public class GiantAndGhost {
	Model[] arr;

	public static void main(String[] args) throws Exception {
		GiantAndGhost gg = new GiantAndGhost();
		int n, c, x, y;
		// 输入重定向
		BufferedInputStream in = new BufferedInputStream(new FileInputStream(
				"in.txt"));
		System.setIn(in);
		Scanner scanner = new Scanner(System.in);
		while (scanner.hasNext()) {
			n = scanner.nextInt();
			gg.arr = new Model[n];
			for (int i = 0; i < n; i++) {
				c = scanner.nextInt();
				x = scanner.nextInt();
				y = scanner.nextInt();
				gg.arr[i] = new Model(c, x, y);
			}
			gg.dfs(0, n);// 区间[0,n)
			System.out.println();
		}
	}

	private void dfs(int st, int ed) {
		int n = ed - st;
		if (n == 2) {// 找到解
			System.out.printf("%s(%d,%d) matches %s(%d,%d)\n",
					arr[st].c == 0 ? "巨人" : "鬼", arr[st].x, arr[st].y,
					arr[st + 1].c == 0 ? "巨人" : "鬼", arr[st + 1].x,
					arr[st + 1].y);
			return;
		}
		int m = st;
		for (int i = st + 1; i < ed; i++) {// 找到y坐标最小的点
			if (arr[i].y < arr[m].y
					|| (arr[i].y == arr[m].y && arr[i].x < arr[m].x))
				m = i;
		}
		int cur = ed - 1;
		Arrays.sort(arr, st, cur, new ModelComparator(arr[cur]));// 按极角大小从小到大排序
		if (arr[st].c != arr[cur].c) {// 第一个和最后一个配对
			swap(arr, st, cur - 1);// 把第一个移动至倒数第二个
			dfs(cur - 1, ed); // 此时可以保证最后两个一定是一对
			dfs(st, cur - 1); // 递归其他
		} else {
			int count1 = 0, count2 = 0;// 巨人和鬼计数
			for (int i = st; i < ed; i++) {
				if (arr[i].c == 0) {
					count1++;
				} else {
					count2++;
				}
				if (count1 == count2)
					break;
			}
			// 此时划分为两个区间 每个区间的鬼和巨人数目相等
			dfs(st, st + count1 * 2);
			dfs(st + count1 * 2, ed);
		}
	}

	private void swap(Model[] arr, int src, int dest) {
		Model m = arr[src];
		arr[src] = arr[dest];
		arr[dest] = m;
	}
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值