转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题目:给出n个城市需要去占领,有m条线段是障碍物,有p个士兵可以用。占领城市有个先后顺序,每个士兵有个背包,占领城市之后,仅能补给一次背包。问背包容量最少是多少,可以用这P个士兵完成任务,起点任意 。
http://acm.hdu.edu.cn/showproblem.php?pid=4606
首先:枚举所有顶点,求一下距离,判断是否与线段相交。然后 floyd预处理最短路
之后是二分答案,判断是否可达
根据占领的先后顺序建边,根据二分的值判断不需要补给是否能够到达。
之后便是判断最小路径覆盖数是否小于等于P。
#include <iostream> #include <queue> #include <algorithm> #include <cstdio> #include <cstring> #include <cmath> using namespace std; typedef long long LL; const int N = 505; const int M = 3000000; const int INF = 100000; const double eps = 1e-7; inline int dcmp(double d){ return d < -eps? -1 : d > eps; } inline double sqr(double d){ return d * d; } struct Point { double x, y; Point (){} Point (double _x,double _y):x(_x),y(_y){} inline bool operator == (const Point &p)const { return (dcmp(x - p.x) == 0 && dcmp(y - p.y) == 0); } inline Point operator - (const Point &p)const { return Point(x - p.x,y - p.y); } inline double operator * (const Point &p)const { return x * p.y - y * p.x; } inline double operator / (const Point &p)const { return x * p.x + y * p.y; } inline double Distance(Point p){ return sqrt(sqr(p.x - x) + sqr(p.y - y)); } void input(){ scanf ("%lf %lf", &x, &y); } }p[N]; struct Line{ Point a,b; void input(){ a.input(); b.input(); } Line(){} Line(Point _a,Point _b):a(_a),b(_b){} inline bool operator == (const Line &l) const{ return (a == l.a && b == l.b) || (a == l.b && b == l.a); } inline double operator * (const Point &p)const { return (b - a) * (p - a); } inline double operator / (const Point &p)const { return (p - a) / (p - b); } inline int SegCrossSeg(const Line &v){ int d1 = dcmp((*this) * v.a); int d2 = dcmp((*this) * v.b); int d3 = dcmp(v * a); int d4 = dcmp(v * b); if((d1 ^ d2) == -2 && (d3 ^ d4) == -2) return 2; return ((d1 == 0 && dcmp((*this) / v.a) <= 0) ||(d2 == 0 && dcmp((*this) / v.b) <= 0) ||(d3 == 0 && dcmp(v / a) <= 0) ||(d4 == 0 && dcmp(v / b) <= 0) ); } }l[N]; int n , m , K , seq[N]; int match[N], vis[N]; double dist[N][N]; int tot , start[N]; struct Edge { int v, next; }e[N * N]; void _add (int u , int v) { e[tot].v = v; e[tot].next = start[u]; start[u] = tot ++; } bool dfs (int u) { for (int i = start[u] ; i != -1 ; i = e[i].next) { int v = e[i].v; if (! vis[v]) { vis[v] = 1; if(match[v] == -1 || dfs(match[v])) { match[v] = u; return true; } } } return false; } int hungry () { int ans = 0; memset (match , -1, sizeof(match)) ; for (int i = 1 ; i <= n ; i ++) { memset (vis , 0 , sizeof(vis)); if (dfs(i)) ans ++; } return ans; } bool check (double mid) { tot = 0 ; memset (start , -1 , sizeof(start)); for (int i =1 ; i <= n ; i ++) { for (int j = i + 1 ; j <= n ; j ++) { if(dist[seq[i]][seq[j]] <= mid) _add (seq[i] , seq[j] + n); } } return n - hungry() <= K; } double solve(){ double l = 0 , r = INF; double ans = -1; int cnt = 50; while(cnt --){ double mid = (l + r) * 0.5; if(check(mid)){ ans = mid; r = mid; } else l = mid; } return ans; } int main(){ int t; scanf ("%d", &t); while (t --){ scanf ("%d%d%d", &n, &m, &K); for (int i = 1 ; i <= n ; i ++){ p[i].input(); } for (int i = 1 ; i <= m ; i ++){ l[i].input(); p[n + (i - 1) * 2 + 1] = l[i].a; p[n + i * 2] = l[i].b; } for (int i = 1 ; i <= n + m * 2 ; i ++){ for (int j = 1 ; j <= n + m * 2 ; j ++){ if(i == j) dist[i][j] = 0.0; else { bool flag = false; for (int k = 1 ; k <= m ; k ++){ if(l[k] == Line(p[i] , p[j])) continue; if (l[k].SegCrossSeg(Line(p[i] , p[j])) == 2) { flag = true; break ; } } if(flag) dist[i][j] = 1e9; else dist[i][j] = p[i].Distance(p[j]); } } } for(int i = 1;i <= n;i ++){ scanf("%d",&seq[i]); } for (int k = 1 ; k <= n + m * 2 ; k ++) { for (int i = 1 ; i <= n + m * 2 ; i ++) { for (int j = 1 ; j <= n + m * 2 ;j ++ ){ dist[i][j] = fmin(dist[i][j] , dist[i][k] + dist[k][j]); } } } double ans = solve(); printf("%.2f\n",ans); } return 0; }