题目大意:平面上有一个$N \times M$的矩形,矩形内有K个点,现给出每个点的坐标,找一条从左边界到右边界的路径,使路径到矩形上下边界及矩形内点的最小距离最大。 20%:$(K<=10)$ 直接暴搜。 50%:$(K<=400)$ 我们以点为圆心画圆。 那么存在一条路径的条件是这些圆没有将半径封死。 我们可以二分圆的半径,每次将相交的圆合并,将上下边界视作点,查询上下边界是否在同一集合内部,若在,则判定失败。 时间复杂度$O(K^2*log_2ANS)$ 100%:$(K<=6000)$ 我们发现二分答案占有相当复杂度,于是我们考虑去掉。 我们把所有点连同上下边界连在一张图里,发现起到限制作用的只用上下边界之间的通路。 答案即为最大值最小的通路上边权的最大值。 做一遍最小生成树,DFS求出上下边界之间的通路上的最大边权。 由于是完全图,我们只能用Prim,并且为了减少内存,边权要现算。 时间复杂度$O(K^2)$ Code: 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<vector> 6 using namespace std; 7 const int N=6003; 8 int n,m,k,U,D; 9 int fi[N],f[N]; 10 long long a[N],b[N]; 11 double d[N]; 12 bool v[N]; 13 vector<int> e[N]; 14 vector<double> l[N]; 15 void add(int x,int y,double z) 16 { 17 e[x].push_back(y); 18 l[x].push_back(z); 19 } 20 double get(int x,int y) 21 { 22 if((x==D&&y==U)||(x==U&&y==D)) return m; 23 if(x==D) return b[y]; 24 if(y==D) return b[x]; 25 if(x==U) return m-b[y]; 26 if(y==U) return m-b[x]; 27 double ans=(a[x]-a[y])*(a[x]-a[y]) (b[x]-b[y])*(b[x]-b[y]); 28 return sqrt(ans); 29 } 30 void dfs(int x,int p) 31 { 32 for(int i=0;i<e[x].size();i ){ 33 int y=e[x][i]; 34 if(y==p) continue; 35 d[y]=max(d[x],l[x][i]); 36 dfs(y,x); 37 } 38 } 39 void Prim() 40 { 41 for(int i=1;i<=k 2;i ) 42 d[i]=99999999; 43 d[1]=0; 44 for(int i=1;i<=k 1;i ){ 45 int x=0; 46 for(int j=1;j<=k 2;j ){ 47 if(!v[j]&&(x==0||d[j]<d[x])) x=j; 48 } 49 v[x]=true; 50 for(int j=1;j<=k 2;j ){ 51 double y=get(x,j); 52 if(!v[j]&&y<d[j]){ 53 d[j]=y;f[j]=x; 54 } 55 } 56 } 57 } 58 int main() 59 { 60 scanf("%d%d%d",&n,&m,&k); 61 U=k 1;D=k 2; 62 for(int i=1;i<=k;i ) 63 scanf("%lld%lld",&a[i],&b[i]); 64 Prim(); 65 for(int i=2;i<=k 2;i ){ 66 add(i,f[i],d[i]);add(f[i],i,d[i]); 67 d[i]=0; 68 } 69 dfs(U,0); 70 printf("%.8lf\n",d[D]/2.0); 71 return 0; 72 }view code 来源:https://www./content-4-401101.html |
|