zoukankan      html  css  js  c++  java
  • #Star Way To Heaven 优化二分 /prim<凉宫春日的忧郁>

    之前是贪心看不粗来,现在二分也看不粗来了,QAQ。。。

    审题清楚,别没看懂题就忙着暴搜,小w不一定走整点,可以走直线

    其实,看到就应该想到二分了

    那么其实二分的答案是作为每个点的半径以圆的形式出现的,一个答案是否成立,看这些障碍圆建出来后,是否还能从左到右联通,那其实是看障碍组成的边界线是否能联通上下的边界。并查集,dfs都可维护。然后是T80的好成绩。

    考虑优化,每次并查集会枚举所有点判距离(毕竟6000^2开不下),这其中是有冗余状态的,考虑这种情况,a可以和他最近的b相连,b可以和他最近的c相连,a也可以和c相连,这是三点其实只用枚举两次就可以,然而枚举c时就多枚举了。优化就显而易见的只枚举四个方向的最近点。

     1 #include<bits/stdc++.h>
     2 #define MAXN 6100
     3 #define reg register 
     4 #define INF 1000000000.0
     5 using namespace std;
     6 inline int read(){
     7     int s=0,w=0;char ch=getchar();
     8     while(ch<'0'||ch>'9')w=(ch=='-'),ch=getchar();
     9     while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    10     return w?-s:s;
    11 }
    12 #define kd (read())
    13 int N,M,K;
    14 int fat[MAXN];
    15 struct dian{
    16     int x,y;
    17 }yd[MAXN];//圆点
    18 int sf[MAXN][4];
    19 inline int find(int x){
    20     if(!fat[x]||fat[x]==x)return x;
    21     return fat[x]=find(fat[x]);
    22 }
    23 void del(){for(reg int i=1;i<=K+2;++i)fat[i]=0; }//清并查集
    24 double l,r;
    25 double cal(int a,int b){
    26     if(a==0||b==0)return INF;
    27     return 1.0*sqrt(1.0*(yd[a].x-yd[b].x)*(yd[a].x-yd[b].x)+
    28     1.0*(yd[a].y-yd[b].y)*(yd[a].y-yd[b].y)); 
    29 }
    30 bool _judge(double dist){
    31     del();
    32     /*for(reg int i=1;i<=K;++i)
    33         for(reg int j=1;j<i;++j)
    34             if(cal(yd[i],yd[j])<2.0*dist)
    35                 fat[find(i)]=find(j);*/
    36     for(reg int i=1;i<=K;++i)
    37         for(reg int k=0;k<4;++k)
    38             if(sf[i][k])
    39                 if(find(i)!=find(sf[i][k]))
    40                     if(cal(i,sf[i][k])<2.0*dist)
    41                         fat[find(i)]=find(sf[i][k]);
    42     for(reg int i=1;i<=K;++i){
    43         if(1.0*M-yd[i].y<2.0*dist)
    44             fat[find(K+1)]=find(i);
    45         if(yd[i].y<2.0*dist)
    46             fat[find(K+2)]=find(i);
    47         if(find(K+2)==find(K+1))
    48             return false;
    49     }
    50     if(find(K+2)==find(K+1))
    51         return false;
    52     return true;
    53 }
    54 int main(){
    55     //freopen("da.in","r",stdin);
    56     N=kd;M=kd;K=kd;
    57     for(reg int i=1,a,b;i<=K;++i)
    58         yd[i].x=kd,yd[i].y=kd;
    59     for(reg int i=1;i<=K;++i){
    60         for(reg int j=1;j<=K;++j)
    61             if(i!=j){
    62                 double dis=cal(i,j);
    63                 if(yd[j].x<=yd[i].x&&yd[j].y<=yd[i].y)
    64                     if(dis<cal(i,sf[i][0]))
    65                         sf[i][0]=j;
    66                 if(yd[j].x>=yd[i].x&&yd[j].y>=yd[i].y)
    67                     if(dis<cal(i,sf[i][1]))
    68                         sf[i][1]=j;
    69                 if(yd[j].x<=yd[i].x&&yd[j].y>=yd[i].y)
    70                     if(dis<cal(i,sf[i][2]))
    71                         sf[i][2]=j;
    72                 if(yd[j].x>=yd[i].x&&yd[j].y<=yd[i].y)
    73                     if(dis<cal(i,sf[i][3]))
    74                         sf[i][3]=j;
    75             }
    76         //for(int k=0;k<4;++k)
    77         //    cout<<sf[i][k]<<" ";
    78         //cout<<endl;
    79     }
    80     l=0;r=1000000.0;
    81     while(r-l>(1e-8)){
    82         double mid=(l+r)*0.5;
    83         if(_judge(mid))l=mid;
    84         else r=mid;
    85     }
    86     printf("%.7lf
    ",r);
    87 }
    View Code

    跑prim,O(n^2),贼快

    其实思想差不多,每个点直接按距离连边,跑出来后找两个边界的路径的最大值除二,表示我找到一个权值最小的边界,在这个边界上最大只能是最大边除二。进一步解释,我过这条障碍线最大要为大边除二。在权值最小的防线上可以这样通过,那么在其他防线上(权值一定比此权值大)也一定能成立

  • 相关阅读:
    常见排序算法-----堆排序
    深度优先搜索和广度优先搜索
    剑指offer整理-------二维数组查找
    常见排序算法-----希尔排序
    log4j日志不能输出到文件
    常见排序算法-----直接插入排序
    从零开始学习springBoot(使用thymeleaf和freemarker模板)
    从零开始学习springBoot(Spring Boot使用Druid和监控配置)
    从零开始学习springBoot(定时任务)
    从零开始学习springBoot(默认静态资源和自定义资源映射)
  • 原文地址:https://www.cnblogs.com/2018hzoicyf/p/11370514.html
Copyright © 2011-2022 走看看