POJ1034最大二分匹配

狗:在从一个指定点到达另一个指定点之间最多可以去访问一个有趣的地方。每个有趣的地方狗最多去访问一次。

人:总是匀速沿直线从一个点去往下一个点,狗的速度不超过猎人速度的两倍。


此题标称应该是用了sqrt,注意精度反而WA

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;

public class Main {
	public static void main(String[] args) {
		new Task().sovle();
	}
}

class Task {
	InputReader in = new InputReader(System.in);
	PrintWriter out = new PrintWriter(System.out);
	final BigInteger two = BigInteger.valueOf(2);

	void sovle() {
		while (in.hasNext()) {
			int n = in.nextInt();
			int m = in.nextInt();
			Point[] bob = new Point[n + 1];
			Point[] dog = new Point[m + 1];
			for (int i = 1; i <= n; i++)
				bob[i] = new Point(in.nextInt(), in.nextInt());
			for (int i = 1; i <= m; i++)
				dog[i] = new Point(in.nextInt(), in.nextInt());
			adj = new List[n + 1];
			for (int i = 1; i < n; i++) {
				double len = bob[i].dist(bob[i + 1]);
				for (int j = 1; j <= m; j++) {
					if (bob[i].dist(dog[j]) + dog[j].dist(bob[i + 1]) <= 2.0* len ) {
						if (adj[i] == null)
							adj[i] = new ArrayList<Integer>() ;
						adj[i].add(j);
					}
				}
			}
			match = new int[m + 1];
			used = new boolean[m + 1];
			dogid = new int[n + 1];
			Arrays.fill(dogid, -1);
			out.println(n + maxMactch(n));
			for (int i = 1; i < n; i++) {
				out.print(bob[i].x + " " + bob[i].y + " ");
				if (dogid[i] != -1)
					out.print(dog[dogid[i]].x + " " + dog[dogid[i]].y + " ");
			}
			out.println(bob[n].x + " " + bob[n].y); 
		}
		out.flush();
	}

	List<Integer>[] adj;
	int[] match;
	int[] dogid;
	boolean[] used;

	boolean dfs(int u) {
		if (adj[u] == null)
			return false;
		for (int v : adj[u]) {
			if (used[v])
				continue;
			used[v] = true;
			if (match[v] == -1 || dfs(match[v])) {
				match[v] = u;
				dogid[u] = v;
				return true;
			}
		}
		return false;
	}

	int maxMactch(int n) {
		int sum = 0;
		Arrays.fill(match, -1);
		for (int u = 1; u < n; u++) {
			Arrays.fill(used, false);
			if (dfs(u))
				sum++;
		}
		return sum;
	}

	class Point {
		int x, y;
		Point(int x, int y) {
			this.x = x;
			this.y = y;
		}

		double dist(Point o) {
			double dx = x - o.x ;
			double dy = y - o.y ;
			return Math.sqrt(dx*dx + dy*dy) ;
		}

	}
}

class InputReader {
	public BufferedReader reader;
	public StringTokenizer tokenizer;

	public InputReader(InputStream stream) {
		reader = new BufferedReader(new InputStreamReader(stream), 32768);
		tokenizer = new StringTokenizer("");
	}

	private void eat(String s) {
		tokenizer = new StringTokenizer(s);
	}

	public String nextLine() {
		try {
			return reader.readLine();
		} catch (Exception e) {
			return null;
		}
	}

	public boolean hasNext() {
		while (!tokenizer.hasMoreTokens()) {
			String s = nextLine();
			if (s == null)
				return false;
			eat(s);
		}
		return true;
	}

	public String next() {
		hasNext();
		return tokenizer.nextToken();
	}

	public int nextInt() {
		return Integer.parseInt(next());
	}

	public long nextLong() {
		return Long.parseLong(next());
	}

	public double nextDouble() {
		return Double.parseDouble(next());
	}

	public BigInteger nextBigInteger() {
		return new BigInteger(next());
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值