http://acm.hdu.edu.cn/showproblem.php?pid=4606
两点之间如果有线段相隔的话,他们的最短路就需要经过线段的端点
把所有线段的端点也加入点数组中,求任意两个点的距离(可达的话,没有其他线段阻挡)
然后对所有的点进行floyd 可以求出任意两点的最短路
然后二分所需容量 根据容量和要求的顺序进行建图,求最小覆盖路径(匈牙利算法)
代码:
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<cmath> #include<set> #include<map> #include<stack> #include<vector> #include<algorithm> #include<queue> #include<stdexcept> #include<bitset> #include<cassert> #include<deque> #include<numeric> //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; typedef long long ll; typedef unsigned int uint; typedef pair<int,int> pp; const double eps=1e-9; const int INF=0x3f3f3f3f; const ll MOD=1000000007; const int N=510; double x[N],y[N]; double dist[N][N]; int schedule[N]; bool visited[N]; bool link[N][N]; int f[N]; int lr(double x1,double y1,double x2,double y2) { double tmp=x1*y2-x2*y1; if(abs(tmp)<eps) return 0; if(tmp>=eps) return 1; return -1; } bool dfs(int x,int n) { for(int i=x+1;i<=n;++i) if(link[x][i]&&!visited[i]) { visited[i]=true; if(f[i]==-1||dfs(f[i],n)) { f[i]=x; return true; } } return false; } int needSoldier(int n,double d) { memset(link,false,sizeof(link)); for(int i=1;i<=n;++i) for(int j=i+1;j<=n;++j) if(d-dist[schedule[i]][schedule[j]]>=eps) link[i][j]=true; memset(f,-1,sizeof(f)); int sum=0; for(int i=1;i<=n;++i) { memset(visited,false,sizeof(visited)); if(dfs(i,n)) ++sum; } return (n-sum); } double bar(int l,int r,int n,int ln) { for(int i=n+1;i<=ln;i=i+2) { double x1=x[r]-x[l]; double y1=y[r]-y[l]; double x2=x[i]-x[l]; double y2=y[i]-y[l]; int k1=lr(x1,y1,x2,y2); x2=x[i+1]-x[l]; y2=y[i+1]-y[l]; int k2=lr(x1,y1,x2,y2); if(k1==0||k2==0||k1==k2) continue; x1=x[i+1]-x[i]; y1=y[i+1]-y[i]; x2=x[l]-x[i]; y2=y[l]-y[i]; k1=lr(x1,y1,x2,y2); x2=x[r]-x[i]; y2=y[r]-y[i]; k2=lr(x1,y1,x2,y2); if(k1==0||k2==0||k1==k2) continue; return INF; } return sqrt((x[r]-x[l])*(x[r]-x[l])+(y[r]-y[l])*(y[r]-y[l])); } int main() { //freopen("data.in","r",stdin); //freopen("1007.in","r",stdin); //freopen("my.out","w",stdout); int T; scanf("%d",&T); while(T--) { int n,m,p; scanf("%d %d %d",&n,&m,&p); for(int i=1;i<=n;++i) scanf("%lf %lf",&x[i],&y[i]); int ln=n; while(m--) { ++ln; scanf("%lf %lf",&x[ln],&y[ln]); ++ln; scanf("%lf %lf",&x[ln],&y[ln]); } for(int i=1;i<=n;++i) scanf("%d",&schedule[i]); for(int i=1;i<=ln;++i) for(int j=i;j<=ln;++j) { if(i==j) dist[i][j]=0.0; else dist[i][j]=dist[j][i]=bar(i,j,n,ln); } for(int l=1;l<=ln;++l) for(int i=1;i<=ln;++i) for(int j=1;j<=ln;++j) if(dist[i][j]>dist[i][l]+dist[l][j]) dist[i][j]=dist[i][l]+dist[l][j]; /* for(int i=1;i<=n;++i) { for(int j=1;j<=n;++j) cout<<dist[i][j]<<" ";cout<<endl; }*/ double l=0.0,r=1000000.0; double ep=1e-6; while(abs(r-l)>ep) { double mid=(l+r)/2; if(needSoldier(n,mid)<=p) r=mid; else l=mid; } printf("%.2lf ",r); } return 0; }