starway(NOIP模拟测试24)

题目大意:平面上有一个$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.cnblogs.com/hz-Rockstar/p/11370517.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值