zoukankan      html  css  js  c++  java
  • cf 744D

    给你红点蓝点,找一个最大的圆,圆里没有蓝点并且至少有一个红点。边界可算可不算。

    一开始没看懂题解,想了好久(一整天)才想明白是枚举弦上点二分半径check角度,看了下clj的代码发现思路都一样就开始写了。

    借鉴了一下clj的代码。

    调了一个多小时。

    几个注意点:看到好多 random_shuffle 的,我没有,也感觉没什么必要。(另外cjl的代码去掉random_shuffle好像会WA。。。)

    极角排序之后可能会遇到很多很多点全在一个角上,这个时候如果排序的话会麻烦,比方说我们要先减后加(哪里麻烦了啊???)

    所以我每次check是不是扫完了完整的一段,也可以理解成我们扫角度不扫点。

    小优化,每次二分先check ans,然后把l设成ans。

    关于怎么求角的范围:两个圆夹起来就是了,初中解析几何?

    千万不要把二分的eps设成1e-8,不然你会在test5tle到自闭并且还根本不知道哪里T了。

    (感冒摸了三天鱼了。不过这题收获还蛮大的)

      1 #include <bits/stdc++.h>
      2 #define rep(x) for(int i=0;i<x;i++)
      3 #define mk(a,b) make_pair(a,b)
      4 using namespace std;
      5 typedef double db;
      6 const db eps=1e-6;
      7 const db pi=acos(-1);
      8 int sign(db k){
      9     if (k>eps) return 1; else if (k<-eps) return -1; return 0;
     10 }
     11 int cmp(db k1,db k2){return sign(k1-k2);}
     12 struct point{
     13     db x,y;
     14     point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};}
     15     point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};}
     16     point operator * (db k1) const{return (point){x*k1,y*k1};}
     17     point operator / (db k1) const{return (point){x/k1,y/k1};}
     18     int operator == (const point &k1) const{return cmp(x,k1.x)==0&&cmp(y,k1.y)==0;}
     19     // 逆时针旋转
     20     point turn(db k1){return (point){x*cos(k1)-y*sin(k1),x*sin(k1)+y*cos(k1)};}
     21     bool operator < (const point k1) const{
     22         int a=cmp(x,k1.x);
     23         if (a==-1) return 1; else if (a==1) return 0; else return cmp(y,k1.y)==-1;
     24     }
     25     db abs(){return sqrt(x*x+y*y);}
     26     db abs2(){return x*x+y*y;}
     27     db dis(point k1){return ((*this)-k1).abs();}
     28     db getw(){return atan2(y,x);}
     29     int getP() const{return sign(y)==1||(sign(y)==0&&sign(x)==-1);}
     30 };
     31 db cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;}
     32 db dot(point k1,point k2){return k1.x*k2.x+k1.y*k2.y;}
     33 db slove(db S){
     34     if(S<0)S+=2*pi;
     35     else if(S>=2*pi) S-=2*pi;
     36     return S;
     37 }
     38 point r[1005],b[1005];
     39 vector<point> p;
     40 int n,m;
     41 vector<pair<db,int>> g;
     42 bool check(int id,db R){
     43     g.clear();
     44     point o = p[id];
     45     rep(n+m){
     46         if(i==id)continue;
     47         point tmp = p[i];
     48         db d = tmp.dis(o);
     49         if(cmp(d,R*2)>=0)continue;
     50         db alf = acos(d/2/R);
     51         db delta = atan2(tmp.y-o.y,tmp.x-o.x);
     52         db l = slove(delta-alf),r=slove(delta+alf);
     53         if(l<r){
     54             g.push_back(mk(l,i<n?2:1));
     55             g.push_back(mk(r,-(i<n?2:1)));
     56         }else{
     57             g.push_back(mk(l,i<n?2:1));
     58             g.push_back(mk(2*pi,-(i<n?2:1)));
     59             g.push_back(mk(0,i<n?2:1));
     60             g.push_back(mk(r,-(i<n?2:1)));
     61         }
     62     }
     63     if(id<n)g.push_back(mk(0,id<n?2:1)),g.push_back(mk(2*pi,-(id<n?2:1)));
     64     sort(g.begin(),g.end());
     65     int rn=0,bn=0;
     66     rep(g.size()){
     67         if((i==g.size()-1||g[i].first!=g[i+1].first)&&rn>0&&bn<=0)return true;
     68         if(abs(g[i].second)==1)
     69             bn+=g[i].second;
     70         else
     71             rn+=g[i].second/2;
     72     }
     73     return false;
     74 }
     75 //枚举弦上点,二分半径,check角度范围,判断是否可行
     76 int main(){
     77     //freopen("zibi.in","r",stdin);
     78     scanf("%d%d",&n,&m);
     79     rep(n) scanf("%lf%lf",&r[i].x,&r[i].y),p.push_back(r[i]);
     80     rep(m) scanf("%lf%lf",&b[i].x,&b[i].y),p.push_back(b[i]);
     81     bool f=0;
     82     rep(n+m)
     83         if(check(i,1e15))
     84             //return 0*printf("%d -1
    ",i);
     85             return 0*printf("-1
    ");
     86     db ans = 0;
     87     //random_shuffle(p.begin(),p.begin()+n);
     88     //random_shuffle(p.begin()+n,p.end());
     89     for(int i=0;i<n+m;i++){
     90         db l=ans,r=1e9;
     91         if(check(i,ans)) {
     92             while (l + eps < r) {
     93                 db mid = (l + r) / 2;
     94                 if (check(i, mid))
     95                     l = mid;
     96                 else r = mid;
     97             }
     98             ans = l;
     99            // printf("%d %.11f
    ",i,ans);
    100         }
    101     }
    102     printf("%.11f
    ",ans);
    103 }
    104 /**
    105 
    106  */
    107 /**
    108 
    109  */
    View Code
    
    
  • 相关阅读:
    《算法竞赛入门经典》 例题35 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)
    《算法竞赛入门经典》 例题35 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)
    《算法竞赛入门经典》 例题35 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)
    SVN分支
    SVN分支
    SVN 版本回退
    SVN 版本回退
    如何在excel中取消合并单元格后内容自动填充?
    如何在excel中取消合并单元格后内容自动填充?
    如何让自己像打王者荣耀一样发了疯、拼了命的学习?
  • 原文地址:https://www.cnblogs.com/MXang/p/10654677.html
Copyright © 2011-2022 走看看