• the 12th UESTC Programming Contest Final Justice is Given by Light (几何+ 二分)


    题目来源:
    http://acm.uestc.edu.cn/#/problem/show/814

    题意:是给你一堆凸包上的点,这些点会形成一个凸多边形,有两个god站在这个多边形上,他们可以释放一个半径为r的魔法火圈,我们要求的就是两个god放出来的火圈完全覆盖这个多边形时的最小半径。

    我的方法是二分半径,然后判断能否覆盖这个多边形是枚举每一条线段,判断每一条线段是否都能被一个圆,或者两个圆完全覆盖,如果能那么这个多边形就能完全被覆盖,只有有一条边不满足覆盖, 则这个多边形不能完全被覆盖。

    其中判断一条跨两个圆的线段能否被两个圆完全覆盖时,用的二分,去找线段上是否存在一个点,同时在两个圆内,如果存在则这条线段能被两个圆完全覆盖。

    代码如下:

    #include <iostream>
    #include <algorithm>
    #include <stdlib.h>
    #include <stdio.h>
    #include <stack>
    #include <string>
    #include <string.h>
    #include<cstring>
    #include <algorithm>
    #include <stdlib.h>
    #include <vector>
    #include <set>
    #include <math.h>
    #include <cmath>
    #include <map>
    #include <queue>
    using namespace std ;
    typedef long long LL ;
    const double EPS = 1e-10;
    const int Max_N = 25;
    double add(double x, double y){
        if (fabs(x+y) <  EPS*( fabs(x)+fabs(y)) )
            return 0;
        return x+y;
    }
    struct Point {
        double x,y;
        Point(){}
        Point(double x, double y):x(x),y(y){}
        double dist(Point p){
            return sqrt( (x-p.x)*(x-p.x) + (y-p.y)*(y-p.y) );
        }
    };
    Point p[Max_N];
    Point mag[3];
    int n;
    // 跨圆的线段, 二分寻找是否存在一个点, 同时在2个圆内
    int judge(Point l,Point r, Point ml, Point mr, double ra){
        Point mid;
        while( fabs(l.dist(r)) > EPS ){
            mid.x= (l.x + r.x) * 0.5;
            mid.y= (l.y + r.y) * 0.5;
            double d1=(ml.dist(mid) - ra);
            double d2=(mr.dist(mid) - ra);
            if(d1<=0 && d2<=0)
                return 1;
            if(d1 <= 0)
                l=mid;
            else
                r=mid;
        }
        return 0;
    }
    int judge1(double r){ // 枚举所有线段,看每条线段是否都能被覆盖
        int i,j;
        for(i=0; i<n-1; i++){
            for(j=i+1;j<n; j++){
                double r1,r2,r3,r4;
                r1=(p[i].dist(mag[1]) - r);
                r2=(p[j].dist(mag[1]) - r);
                r3=(p[i].dist(mag[2]) - r);
                r4=(p[j].dist(mag[2]) - r);
                if( (r1<= 0 && r2<= 0) || (r3<=0 && r4<=0) )
                    continue;
                if( r1 <=0 && r4<=0 ){
                    if(judge(p[i] ,p[j],mag[1],mag[2], r)) // judge判断一条跨线是否被覆盖
                        continue;
                }
                if(r2<=0 && r3<=0){
                    if(judge( p[i],p[j],mag[2],mag[1],r ))
                        continue;
                }
                return 0;
            }
        }
        return 1;
    }
    int main(){
        while(~scanf("%d" ,&n)){
            for(int i=0; i<n; i++)
                scanf("%lf%lf",&p[i].x, &p[i].y );
            for(int i=1; i<=2; i++)
                scanf("%lf%lf",&mag[i].x, &mag[i].y);
            double ll=0.0, lr=4000.0; // lr不能开太小, 可以开大些
            double md;
            while(ll+ EPS <lr ){ //二分半径
                md=(ll + lr) * 0.5;
                if(judge1(md))
                    lr=md;
                else
                    ll=md;
            }
            printf("%.3lf
    ",md);
        }
    }
  • 相关阅读:
    括号匹配(有点复杂,因为它讲得详细)
    A+B/A*B求A和B
    构造哈夫曼树
    用栈实现进制转换
    实现二叉树各种基本运算的算法
    十六进制加法
    求二叉树中叶子结点到根结点的路径
    SilverLight4常见问题及解决办法
    Silverlight中自定义控件
    Silverlight发布时的优化工作
  • 原文地址:https://www.cnblogs.com/zn505119020/p/3668277.html
Copyright © 2020-2023  润新知