zoukankan      html  css  js  c++  java
  • POJ 3549 GSM phone(圆+扫描线+最短路)

    题目意思是求起点s到终点s的最短路,但是只能在圆的内部和边上走。一种可以想到的方法就是求出所有的交点,然后两两连边并验证合法性,但是这样的交点数规模有n2

    我们可以观察发现,我们在圆求并构成的图形中,在其内部的点是不可能成为最短路上的点,只可能是沿着边上的点擦着经过,所以我们需要把在圆内部的所有点都给扣掉,同样可以证明这样的点的规模只有n个,接下来只需要暴力连边,但是连边的时候需要验证这样的点对是否沿着直线可达。我是直接将这条线段暴力和所有圆求交点,左侧端点计为1,右侧端点计为-1,然后用类似于扫描线的做法sort一遍,最后判断线段的两端是否被这个区间包含即可。

    最后跑一边dijk就求出答案。

    这个方法感觉不是很好.... 还有比我快20倍的orz... 

    如果扣的是灰色点那么规模有n2

    如果是外侧点只有n个,绿色点即为可用点,红色和橙色为两条路,则最短路必然擦过外侧点或者起点终点直接相连

     

      1 //      ——By DD_BOND
      2 
      3 //#include<bits/stdc++.h>
      4 //#include<unordered_map>
      5 //#include<unordered_set>
      6 #include<functional>
      7 #include<algorithm>
      8 #include<iostream>
      9 //#include<ext/rope>
     10 #include<iomanip>
     11 #include<climits>
     12 #include<cstring>
     13 #include<cstdlib>
     14 #include<cstddef>
     15 #include<cstdio>
     16 #include<memory>
     17 #include<vector>
     18 #include<cctype>
     19 #include<string>
     20 #include<cmath>
     21 #include<queue>
     22 #include<deque>
     23 #include<ctime>
     24 #include<stack>
     25 #include<map>
     26 #include<set>
     27 #include<cassert>
     28 
     29 #define fi first
     30 #define se second
     31 #define pb push_back
     32 #define MP make_pair
     33 
     34 #pragma GCC optimize(3)
     35 #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
     36 
     37 using namespace std;
     38 
     39 typedef long double db;
     40 typedef long long ll;
     41 typedef pair<db,db> Pd;
     42 typedef pair<int,int> P;
     43 typedef pair<ll,ll> Pll;
     44 
     45 const db eps=1e-8;
     46 const int MAXN=1e5+10;
     47 const db pi=acos(-1.0);
     48 const ll INF=0x3f3f3f3f3f3f3f3f;
     49 
     50 inline int dcmp(db x){
     51     if(fabs(x)<eps) return 0;
     52     return (x>0? 1: -1);
     53 }
     54 
     55 inline db Sqrt(db x){
     56     return x>0? sqrt(x): 0;
     57 }
     58 
     59 inline db sqr(db x){ return x*x; }
     60 
     61 struct Point{
     62     db x,y;
     63     Point(){ x=0,y=0; }
     64     Point(db _x,db _y):x(_x),y(_y){}
     65     void input(){
     66         double _x,_y;
     67         scanf("%lf%lf",&_x,&_y);
     68         x=_x,y=_y;
     69     }
     70     void output(){ printf("%.2f %.2f
    ",(double)x,(double)y); }
     71     friend istream &operator >>(istream &os,Point &b){
     72         os>>b.x>>b.y;
     73         return os;
     74     }
     75     friend ostream &operator <<(ostream &os,Point &b){
     76         os<<b.x<<' '<<b.y;
     77         return os;
     78     }
     79     bool operator ==(const Point &b)const{
     80         return (dcmp(x-b.x)==0&&dcmp(y-b.y)==0);
     81     }
     82     bool operator !=(const Point &b)const{
     83         return !((dcmp(x-b.x)==0&&dcmp(y-b.y)==0));
     84     }
     85     bool operator <(const Point &b)const{
     86         return (dcmp(x-b.x)==0? dcmp(y-b.y)<0 : x<b.x);
     87     }
     88     db operator ^(const Point &b)const{     //叉积
     89         return x*b.y-y*b.x;
     90     }
     91     db operator *(const Point &b)const{     //点积
     92         return x*b.x+y*b.y;
     93     }
     94     Point operator +(const Point &b)const{
     95         return Point(x+b.x,y+b.y);
     96     }
     97     Point operator -(const Point &b)const{
     98         return Point(x-b.x,y-b.y);
     99     }
    100     Point operator *(db a){
    101         return Point(x*a,y*a);
    102     }
    103     Point operator /(db a){
    104         return Point(x/a,y/a);
    105     }
    106     db len2(){  //长度平方
    107         return sqr(x)+sqr(y);
    108     }
    109     db len(){   //长度
    110         return Sqrt(len2());
    111     }
    112     Point change_len(db r){ //转化为长度为r的向量
    113         db l=len();
    114         if(dcmp(l)==0)  return *this;  //零向量
    115         return Point(x*r/l,y*r/l);
    116     }
    117     Point rotate_left(){    //逆时针旋转90度
    118         return Point(-y,x);
    119     }
    120     Point rotate_right(){   //顺时针旋转90度
    121         return Point(y,-x);
    122     }
    123 };
    124 
    125 inline db cross(Point a,Point b){   //叉积
    126     return a.x*b.y-a.y*b.x;
    127 }
    128 
    129 inline db dot(Point a,Point b){ //点积
    130     return a.x*b.x+a.y*b.y;
    131 }
    132 
    133 inline db dis(Point a,Point b){ //两点的距离
    134     Point p=b-a;    return p.len();
    135 }
    136 
    137 struct Line{
    138     Point s,e;
    139     Line(){}
    140     Line(Point _s,Point _e):s(_s),e(_e){} //两点确定直线
    141     void input(){
    142         s.input();
    143         e.input();
    144     }
    145     db length(){    //线段长度
    146         return dis(s,e);
    147     }
    148 };
    149 
    150 inline db point_to_line(Point p,Line a){   //点到直线距离
    151     return fabs(cross(p-a.s,a.e-a.s)/a.length());
    152 }
    153 
    154 inline Point projection(Point p,Line a){       //点在直线上的投影
    155     return a.s+(((a.e-a.s)*dot(a.e-a.s,p-a.s))/(a.e-a.s).len2());
    156 }
    157 
    158 struct Circle{
    159     Point p;
    160     db r;
    161     Circle(){}
    162     void input(){
    163         p.input();
    164         double _r;
    165         scanf("%lf",&_r);
    166         r=_r;
    167     }
    168 };
    169 
    170 inline int relation(Point p,Circle a){ //点和圆的位置关系  0:圆外    1:圆上   2:圆内
    171     db d=dis(p,a.p);
    172     if(dcmp(d-a.r)==0)  return 1;
    173     return (dcmp(d-a.r)<0? 2: 0);
    174 }
    175 
    176 inline int relation(Line a,Circle b){  //直线和圆的位置关系  0:相离   1:相切   2:相交
    177     db p=point_to_line(b.p,a);
    178     if(dcmp(p-b.r)==0)  return 1;
    179     return (dcmp(p-b.r)<0? 2: 0);
    180 }
    181 
    182 inline int relation(Circle a,Circle v){    //圆和圆的位置关系  1:内含  2:内切  3:相交   4:外切   5:相离
    183     db d=dis(a.p,v.p);
    184     if(dcmp(d-a.r-v.r)>0)   return 5;
    185     if(dcmp(d-a.r-v.r)==0)  return 4;
    186     db l=fabs(a.r-v.r);
    187     if(dcmp(d-l)>0)     return 3;
    188     if(dcmp(d-l)==0)    return 2;
    189     return 1;
    190 }
    191 
    192 inline int circle_intersection(Circle a,Circle v,Point &p1,Point &p2){ //两个圆的交点
    193     int rel=relation(a,v);                                      //返回交点个数,保存在引用中
    194     if(rel==1||rel==5)  return 0;
    195     db d=dis(a.p,v.p);
    196     db l=(d*d+a.r*a.r-v.r*v.r)/(2*d);
    197     db h=Sqrt(a.r*a.r-l*l);
    198     Point tmp=a.p+(v.p-a.p).change_len(l);
    199     p1=tmp+((v.p-a.p).rotate_left().change_len(h));
    200     p2=tmp+((v.p-a.p).rotate_right().change_len(h));
    201     if(rel==2||rel==4)  return 1;
    202     return 2;
    203 }
    204 
    205 inline int line_circle_intersection(Line v,Circle u,Point &p1,Point &p2){  //直线和圆的交点
    206     if(!relation(v,u))  return 0;                                   //返回交点个数,保存在引用中
    207     Point a=projection(u.p,v);
    208     db d=point_to_line(u.p,v);
    209     d=Sqrt(u.r*u.r-d*d);
    210     if(dcmp(d)==0){
    211         p1=a,p2=a;
    212         return 1;
    213     }
    214     p1=a+(v.e-v.s).change_len(d);
    215     p2=a-(v.e-v.s).change_len(d);
    216     return 2;
    217 }
    218 
    219 typedef pair<db,int>pdi;
    220 typedef pair<Point,int> pd;
    221 
    222 vector<pdi>edge[MAXN];
    223 
    224 db d[MAXN];
    225 pd st[MAXN];
    226 bool mark[MAXN];
    227 Circle circle[MAXN];
    228 Point s,t,it1,it2,inter[MAXN],point[MAXN];
    229 
    230 priority_queue<pdi,vector<pdi>,greater<pdi> >q;
    231 
    232 bool cmp(pd a,pd b){
    233     if(a==b)    return a.se>b.se;
    234     return a<b;
    235 }
    236 
    237 int main(void){
    238     s.input();  t.input();
    239     int n,m=1,cnt=1;  scanf("%d",&n);
    240     for(int i=1;i<=n;i++)   circle[i].input();
    241     for(int i=1;i<=n;i++)
    242         for(int j=i+1;j<=n;j++){
    243             int p=relation(circle[i],circle[j]);
    244             if(p==2||p==3||p==4){
    245                 circle_intersection(circle[i],circle[j],it1,it2);
    246                 point[m++]=it1,point[m++]=it2;
    247             }
    248         }
    249     sort(point+1,point+m);
    250     m=unique(point+1,point+m)-point;
    251     for(int i=1;i<m;i++)
    252         for(int j=1;j<=n;j++)
    253             if(relation(point[i],circle[j])==2){
    254                 mark[i]=1;
    255                 break;
    256             }
    257     for(int i=1;i<m;i++)
    258         if(mark[i]==0)
    259             point[cnt++]=point[i];
    260     m=cnt;  point[0]=s,point[m]=t;
    261     for(int i=0;i<=m;i++)
    262         for(int j=i+1;j<=m;j++){
    263             int p=0;
    264             Line l(point[i],point[j]);
    265             Point p1=point[i],p2=point[j];
    266             if(p2<p1)   swap(p1,p2);
    267             for(int k=1;k<=n;k++){
    268                 Circle c=circle[k];
    269                 if(relation(l,c)){
    270                     line_circle_intersection(l,c,it1,it2);
    271                     if(it2<it1) swap(it1,it2);
    272                     st[p++]=pd(it1,1);
    273                     st[p++]=pd(it2,-1);
    274                 }
    275             }
    276             int found=0;
    277             sort(st,st+p,cmp);
    278             for(int k=0,sum=0,start=0;k<p;k++){
    279                 sum+=st[k].se;
    280                 if(sum==0){
    281                     if(!(p1<st[start].fi)&&!(st[k].fi<p2)) found=1;
    282                     start=k+1;
    283                 }
    284             }
    285             if(found){
    286                 edge[i].pb(pdi(l.length(),j));
    287                 edge[j].pb(pdi(l.length(),i));
    288             }
    289         }
    290     for(int i=1;i<=m;i++)   d[i]=1e20;
    291     q.push(pdi(0,0));
    292     while(!q.empty()){
    293         pdi p=q.top();  q.pop();
    294         if(dcmp(d[p.se]-p.fi)<0)   continue;
    295         for(int i=0;i<edge[p.se].size();i++){
    296             int v=edge[p.se][i].se;
    297             db val=edge[p.se][i].fi;
    298             if(dcmp(d[p.se]+val-d[v])<0){
    299                 d[v]=d[p.se]+val;
    300                 q.push(pdi(d[v],v));
    301             }
    302         }
    303     }
    304     printf("%.5f
    ",(double)d[m]);
    305     return 0;
    306 }
  • 相关阅读:
    解决端口被占用
    Oracle查询所有表的字段明细
    Spring cron表达式
    Java爬取12306余票
    Activiti工作流框架——快速上手
    ERROR 1045 (28000): Access denied for user 'xxx'@'localhost' (using password: YES)【奇葩的bug】
    一分钟学会JavaMail(假)__手动滑稽
    通过Servlet实现汉字验证码
    使用ServletContext对象读取资源文件
    编写一个简单的java服务器程序
  • 原文地址:https://www.cnblogs.com/dd-bond/p/11622268.html
Copyright © 2011-2022 走看看