标签:
2 2 1 1 0 0 2 0 1 1 1 -1 2 1 4 2 2 0 1 5 1 8 0 1 -1 0 0 2 0 6 0 6 3 1 2 3 4
2.83 3.41HintFor the second sample case, the best strategy is: step 1: air-drop soldier 1 to city 1, city 1 occupied; step 2: air-drop soldier 2 to city 2, city 2 occupied; step 3: soldier 2 moves from city 2 to city 3, city 3 occupied, and 3.41 units of food needed; step 4: soldier 1 moves from city 1 to city 4, city 4 occupied, and 2.41 units food needed. Therefore, the minimal volume of bags is 3.41.
题意:有n个城市,然后有p个士兵要去占领,路上有m个路障,都是线段,士兵
不能越过路障前进。每个士兵都有相同容量大小的一个干粮袋,每到一个城市他
就能补充满自己的干粮袋。中途走路时走一个单位长度就消耗一个单位的干粮。
现在问的是这些个干粮袋最小的容量是多少,前提是保证p个士兵能占领完这n个
城市,城市被占领顺序也是题目给好的,必须遵守。
思路:P个士兵占领n个城市,可以看成p个士兵走出了p个路径,覆盖了所有的点。
最小路径覆盖的要求之一就是有向,无环,在题目中的体现就是城市被占领时必须
有顺序。然后枚举所有顶点,求一下距离,判断是否与线段相交。然后 floyd预处
理最短路,之后是二分答案,判断是否可达根据占领的先后顺序建边,根据二分
的值判断不需要补给是否能够到达。判断条件为最小路径覆盖数是否小于等于P。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; const double eps=1e-7; const double inf=999999999; const int maxn=310; struct point { double x,y; point() {} point(double _x,double _y):x(_x),y(_y) {} friend point operator - (const point &p,const point &q) { return point(p.x-q.x,p.y-q.y); } friend bool operator == (const point &p,const point &q) { if(fabs(p.x-q.x)<eps && fabs(p.y-q.y)<eps) return true; return false; } } A[maxn],B[maxn],C[maxn]; int n,m,p,cnt,a[maxn],match[maxn]; double dis[maxn][maxn]; bool con[maxn][maxn],visited[maxn]; double dcheng(point p,point q) { return (p.x*q.y-p.y*q.x); } bool cross(point x1,point y1,point x2,point y2) { double t1=dcheng(y1-x1,x2-x1); double t2=dcheng(y1-x1,y2-x1); double t3=dcheng(y2-x2,x1-x2); double t4=dcheng(y2-x2,y1-x2); if(t1*t2<0 && t3*t4<0) return true; return false; } double dist(point p,point q) { return sqrt((p.x-q.x)*(p.x-q.x)+(p.y-q.y)*(p.y-q.y)); } void initial() { for(int i=0; i<maxn; i++) for(int j=0; j<maxn; j++) { if(i==j) dis[i][j]=0; else dis[i][j]=inf; } } void input() { scanf("%d %d %d",&n,&m,&p); cnt=n; for(int i=1; i<=n; i++) scanf("%lf %lf",&A[i].x,&A[i].y); for(int i=0; i<m; i++) { scanf("%lf %lf %lf %lf",&B[i].x,&B[i].y,&C[i].x,&C[i].y); A[++cnt]=B[i]; A[++cnt]=C[i]; } for(int i=0; i<n; i++) scanf("%d",&a[i]); } void ready() { for(int i=1; i<=cnt; i++) for(int j=i+1; j<=cnt; j++) { bool flag=1; for(int k=0; k<m; k++) { if((A[i]==B[k] && A[j]==C[k]) || (A[i]==C[k] && A[j]==B[k])) continue; if(cross(A[i],A[j],B[k],C[k])) { flag=0; break; } } if(flag) dis[i][j]=dis[j][i]=dist(A[i],A[j]); } } void floyd() { for(int k=1;k<=cnt;k++) for(int i=1;i<=cnt;i++) for(int j=1;j<=cnt;j++) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); } void build(double r) { memset(con,0,sizeof(con)); memset(match,-1,sizeof(match)); for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) { double t=dis[a[i]][a[j]]; if(t<r || fabs(t-r)<eps) con[a[i]][a[j]]=1; } } bool dfs(int x) { for(int i=1;i<=n;i++) { if(con[x][i] && !visited[i]) { visited[i]=1; if(dfs(match[i]) || match[i]==-1) { match[i]=x; return true; } } } return false; } bool judge() { int ret=0; for(int i=1;i<=n;i++) { memset(visited,0,sizeof(visited)); if(dfs(i)) ret++; } if(n-ret<=p) return true; return false; } void solve() { floyd(); double l=0.0,r=inf; while(l+eps<r) { double mid=(l+r)/2; build(mid); if(judge()) r=mid; else l=mid; } printf("%.2lf\n",r); } int main() { int T; scanf("%d",&T); while(T--) { initial(); input(); ready(); solve(); } return 0; }
hdu 4606 Occupy Cities(线段相交+最小路径覆盖+二分)
标签:
原文地址:http://blog.csdn.net/u012596172/article/details/43054087