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