hdu 4606(线段相交 + 最短路 + 最小路径覆盖)

题目链接

多校第一场的题目, 这题很综合, 考察了很多点, 首先对于这种二维平面上带有障碍的最短路在LRJ的白书上有提到, 然后对于后一部分由于城市的占领有顺序所以得到了一个DAG, 然后再二分相邻两点间的最长距离每次用最小路径覆盖判断人数是否小于等于给定人数就可以了。。。。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>

using namespace std;

const int N = 105;
const double INF = 1e16;
const double eps = 1e-8;

struct Point {
	int x, y;

	Point (int a= 0, int b = 0) {
		x = a, y = b;
	}
};

typedef Point Vector;
typedef long long LL;

Vector operator - (Point a, Point b) {
	return Vector(a.x - b.x, a.y - b.y);
}

int cross(Vector a, Vector b) {
	return a.x * b.y - a.y * b.x;
}

bool intersect(Point a1, Point a2, Point b1, Point b2) {
	int c1 = cross(a2 - a1, b1 - a1), c2 = cross(a2 - a1, b2 - a1),
	c3 = cross(b2 - b1, a1 - b1), c4 = cross(b2 - b1, a2 - b1);

	return (LL)c1 * c2 < 0 && (LL)c3 * c4 < 0;
}

inline double pow2(int x) {
	return (double)x * x;
}

double dist(Point a, Point b) {
	return sqrt(pow2(a.x - b.x) + pow2(a.y - b.y));
}

Point A[N], st[N], ed[N];
int ord[N];
double res[N * N];
Point all[N * 3];

double dis[505][505];

const int M = 100005;

struct Match {
	struct Edge {
		int v;
		Edge* next;

		void init(int a, Edge* e) {
			this->v = a, next = e;
		}
	};

	Edge* it;
	Edge* head[N];
	Edge E[M];
	bool Y[N];
	int n, res;
	int px[N], py[N];

	void init(int n) {
		this->n = n;
		for(int i = 0; i < n; i++)
			head[i] = 0;
		fill(px, px + n, -1);
		fill(py, py + n, -1);
		it = E;
	}

	void add(int u, int v) {
		it->init(v, head[u]);
		head[u] = it++;
	}

	bool find(int u) {
		for (Edge* e = head[u]; e; e = e->next) {
			int v = e->v;
			if (!Y[v]) {
				Y[v] = 1;
				if (py[v] == -1 || find(py[v])) {
					py[v] = u;
					px[u] = v;
					return 1;
				}
			}
		}
		return 0;	
	}

	void run() {
		res = 0;
		for (int i = 0; i < n; i++) {
			fill(Y, Y + n, 0);
			if (find(i)) res++;
		}
	}
}G;

int n;

bool jud(double val, int tar) {
	G.init(n);
	for (int i = 0; i < n; i++)
		for (int j = i + 1; j < n; j++) {
			int u = ord[i], v = ord[j];
			if (dis[u][v] < val + eps)
				G.add(u, v);		
		}
	G.run();
	return n - G.res <= tar;
}

int main() {
	int m, p, test;
	scanf("%d", &test);
	while (test--) {
		scanf("%d%d%d", &n, &m, &p);

		int tot = 0;
		for (int i = 0; i < n; i++) {
			scanf("%d%d", &A[i].x, &A[i].y);
			all[tot].x = A[i].x, all[tot].y = A[i].y;
			tot++;
		}

		for (int i = 0; i < m; i++) {
			scanf("%d%d%d%d", &st[i].x, &st[i].y, &ed[i].x, &ed[i].y);
			all[tot].x = st[i].x, all[tot].y = st[i].y;
			tot++;
			all[tot].x = ed[i].x, all[tot].y = ed[i].y;
			tot++;
		}

		for (int i = 0; i < n; i++) {
			scanf("%d", ord + i);
			ord[i]--;
		}

		bool tmp;

		for (int i = 0; i < tot; i++)
			for (int j = 0; j < tot; j++)
				if (i == j)
					dis[i][j] = 0;
				else
					dis[i][j] = INF;

		for (int i = 0; i < tot; i++) {
			for (int j = i + 1; j < tot; j++) {
				tmp = 1;
				for (int k = 0; k < m; k++) {
					if (intersect(all[i], all[j], st[k], ed[k])) {
						tmp = 0;
						break;
					}
				}
				
				if (!tmp) continue;
				else {
					dis[j][i] = dis[i][j] = min(dist(all[i], all[j]), dis[i][j]);
				}
			}
		}

		for (int k = 0; k < tot; k++)
			for (int i = 0; i < tot; i++)
				for (int j = 0; j < tot; j++) {
					dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
				}

		int c = 0;
		res[c++] = 0;
		for (int i = 0; i < n; i++) {
			for (int j = i + 1; j < n; j++) {
				res[c++] = dis[i][j];	

			}
		}

		sort(res, res + c);
		c = unique(res, res + c) - res;

		int L = 0, R = c - 1;

		while (L <= R) {
			int mid = L + R >> 1;
			if (jud(res[mid], p)) 
				R = mid - 1;
			else
				L = mid + 1;
		}

		printf("%.2lf\n", res[L]);
									
	}	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值