uva 11177 Fighting Against a Polygonal Monster(凸包与圆的面积交)

Problem C
Fighting against a Polygonal Monster
Input: Standard Input
Output: Standard Output

You're fighting against a monster. You have a special weapon that can shoot a laser beam. The laser beam can be seen as a cylinder along the z-axis, So when look from above the XY plane, the laser beam is actually a circle centered at (0,0) (yes, you cannot change the position of center). The monster is a convex polygon (well, you may think of it as a very thin prism) with n vertices surrounding the origin (i.e. (0,0) is strictly inside the monster, not on his boundary).

You know that, when the common area of the laser beam and the monster is at least R, the monster dies. Since larger laser beam consumes more power, you're interested in the minimum radius of the laser beam.

Write a program to find the minimum radius. It is guaranteed that (0 £ R £ A), where A is the area of the monster.

Input
The input consists at most 10 cases. Each case starts with a single integer n (3 £ n £ 50) and a floating-point number R followed by n lines of two real numbers: the coordinates of the monster. The points are arranged in counter-clockwise order or clockwise order. The last test case is followed by a single zero, which should not be processed. The meaning of N and R are given in the problem statement.

Output
For each test case, print the case number and the minimum radius, to 2 decimal places. Inputs will be such that small precision errors will not change the visible output if you use double-precision floating-point numbers.

Sample Input
3 1.60
-1 -1
1 -1
0 1
0


 Output for Sample Input

Case 1: 0.93


Problem setter: Rujia Liu
Alternative Solutions: Wenbin Tang, Yiming Li

Originally used in the Sichuan Team Selection Contest for NOI, 2006.


题意:有个凸N边形,一定包含原点。 然后有一个以原点为圆心的圆,要使圆与凸边形的面积交等于S,问圆的半径应该为多大。


思路:先将凸包极角排序,二分圆的半径。然后将凸多边形对于原点进行三角剖分。

对于每个三角形OAB和圆的位置关系有4种情况,

1.A,B在圆内,则计算三角形的面积。

2.A,B有一个在圆内,则计算一个三角形和一个扇形的面积。

3.A,B在圆外,如果线段AB与圆有交点,则计算两个扇形和一个三角形的面积。否则只需计算一个扇形的面积。


代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <bitset>
#include <algorithm>
#include <set>
#include <string>
#include <vector>
#include <list>
#include <stack>
#include <queue>
#include <deque>
using namespace std;

#define LL long long


const double eps = 1e-10;
const double pi = acos(-1.0);

int cmp(double x) {
    if(fabs(x) < eps) return 0;
    if(x > 0)return 1;
    return -1;
}

inline double sqr(double x) {
    return x * x;
}



struct point {
    double x, y;
    point(){}
    point(double a, double b): x(a), y(b) {}
    void input(){
        scanf("%lf%lf",&x,&y);
    }

    friend point operator + (const point &a, const point &b) {
        return point(a.x + b.x, a.y + b.y);
    }

    friend point operator - (const point &a, const point &b) {
        return point(a.x - b.x, a.y - b.y);
    }

    friend bool operator == (const point &a, const point &b) {
        return cmp(a.x - b.x) == 0 && cmp(a.y - b.y) == 0;
    }

    friend bool operator < (const point &a, const point& b) {
        return cmp(a.x - b.x) < 0 || cmp(a.x - b.x) == 0 && cmp (a.y - b.y) < 0;
    }

    friend point operator * (const point &a, const double &b) {
        return point(a.x * b, a.y * b);
    }

    friend point operator * (const double &a, const point &b) {
        return point(a * b.x, a * b.y);
    }

    friend point operator / (const point &a, const double &b) {
        return point(a.x / b, a.y / b);
    }
    double norm(){
        return sqrt(sqr(x) + sqr(y));
    }
};

double det(const point &a, const point &b) {
    return a.x * b.y - a.y * b.x;
}

double dot(const point &a, const point &b) {
    return a.x * b.x + a.y * b.y;
}

double dist(const point &a, const point &b) {
    return (a - b).norm();
}

double Angle(point a, point b) {
    if(cmp(dot(a, b) - a.norm() * b.norm()) == 0) return 0;
    if(cmp(dot(a, b) + a.norm() * b.norm()) == 0) return pi;
    return acos(dot(a,b) / a.norm() / b.norm()); 
}

double angle(point p) {
    return atan2(p.y, p.x);
}

point rotate_point(const point &p, double A){
    double tx = p.x, ty = p.y;
    return point(tx * cos(A) - ty * sin(A), tx * sin(A) + ty * cos(A));
}

point rotate_point(const point &p, double sint, double cost) {
    double tx = p.x, ty = p.y;
    return point(tx * cost - ty * sint, tx * sint + ty * cost);
}

struct line {
    point a, b;
    line(){}
    line(point x, point y):a(x),b(y){}
    void input() {
        a.input();
        b.input();
    }
};



void point_pro_line(const point p, const point s, const point t, point &cp) {  
    double r = dot(t - s, p - s) / dot (t - s, t - s);
    cp = s + r * (t - s);
}

bool point_pro_segment(const point p, const point s, const point t, point &cp) {
    if(cmp(dot(p - s, t - s))<0) {
        cp = s;
        return 0;
    }
    if(cmp(dot(p - t, s - t))<0) {
        cp = t;
        return 0;
    }

    double r = dot(t - s, p - s) / dot (t - s, t - s);
    cp = s + r * (t - s);
    return 1;
}

bool point_on_segment(point p, point s, point t) {
    return cmp(det(p - s, t - s))== 0 && cmp(dot(p - s, p - t)) <= 0;
}

bool parallel(line a, line b) {
    return !cmp(det(a.a - a.b, b.a - b.b));
}

bool line_cross_line(line a, line b, point &res){
    if(parallel(a, b)) return false;
    double s1 = det(a.a - b.a, b.b - b.a);
    double s2 = det(a.b - b.a, b.b - b.a);
    res = (s1 * a.b - s2 * a.a) / (s1 - s2);
    return true;
}

int segment_cross_segment(const point& a1,const point& a2,const point& b1,const point& b2, point& res) {
    double c1 = det(a2 - a1, b1 - a1);
    double c2 = det(a2 - a1, b2 - a1);
    double c3 = det(b2 - b1, a1 - b1);
    double c4 = det(b2 - b1, a2 - b1);
    if (cmp(c1) * cmp(c2) < 0 && cmp(c3) * cmp(c4) < 0) {
        res.x = (b1.x * c2 - b2.x * c1) / (c2 - c1);
        res.y = (b1.y * c2 - b2.y * c1) / (c2 - c1);
        return 1;
    }

    if(point_on_segment(a1, b1, b2)) {
        res = a1;
        return 2;
    }

    if(point_on_segment(a2, b1, b2)) {
        res = a2;
        return 2;
    }

    if(point_on_segment(b1, a1, a2)) {
        res = b1;
        return 2;
    }

    if(point_on_segment(b2, a1, a2)) {
        res = b2;
        return 2;
    }

    return 0;
}

int segment_cross_segment(const line& l1, const line& l2, point& res) {
    point a1 = l1.a, a2 = l1.b, b1 = l2.a, b2 = l2.b;
    double c1 = det(a2 - a1, b1 - a1);
    double c2 = det(a2 - a1, b2 - a1);
    double c3 = det(b2 - b1, a1 - b1);
    double c4 = det(b2 - b1, a2 - b1);
    if (cmp(c1) * cmp(c2) < 0 && cmp(c3) * cmp(c4) < 0) {
        res.x = (b1.x * c2 - b2.x * c1) / (c2 - c1);
        res.y = (b1.y * c2 - b2.y * c1) / (c2 - c1);
        return 1;
    }

    if(point_on_segment(a1, b1, b2)) {
        res = a1;
        return 2;
    }

    if(point_on_segment(a2, b1, b2)) {
        res = a2;
        return 2;
    }

    if(point_on_segment(b1, a1, a2)) {
        res = b1;
        return 2;
    }

    if(point_on_segment(b2, a1, a2)) {
        res = b2;
        return 2;
    }

    return 0;
}


struct circle {
    point c;
    double r;
    circle() {}
    circle(point _c, double _r): c(_c), r(_r) {}
    void input() {
        c.input();
        scanf("%lf", &r);
    }
    double perimeter() {
        return 2 * pi * r;
    }

    double area() {
        return sqr(r) * pi;
    }
};

bool point_on_circle(const point& p, const circle& c) {
    return cmp((p - c.c).norm() - c.r) == 0;
}

bool point_in_circle(const point& p, const circle& c) {
    return cmp((p - c.c).norm() - c.r) < 0;
}

int circle_cross_line(circle C, line l, double &t1, double &t2, point res[]) {
    double a = l.b.x - l.a.x;
    double b = l.a.x - C.c.x;
    double c = l.b.y - l.a.y;
    double d = l.a.y - C.c.y;
    double e = sqr(a) + sqr(c);
    double f = 2 * (a * b + c * d);
    double g = sqr(b) + sqr(d) - sqr(C.r);
    double delta = f * f - 4 * e * g;
    if(cmp(delta) < 0) return 0;
    if(cmp(delta) == 0) {
        t1 = t2 = -f / (2 * e);
        res[0] = point(l.a.x + t1 * a, l.a.y + t1 * c);
        return 1;
    }

    t1 = (-f - sqrt(delta)) / (2 * e);
    t2 = (-f + sqrt(delta)) / (2 * e);
    res[0] = point(l.a.x + t1 * a, l.a.y + t1 * c);
    res[1] = point(l.a.x + t2 * a, l.a.y + t2 * c);
    return 2;
}

int circle_cross_circle(circle C1, circle C2, point res[]) {
    double d = (C1.c - C2.c).norm();
    if(cmp(C1.r + C2.r - d) < 0 || cmp(fabs(C1.r - C2.r) - d) > 0) return 0;
    if(cmp(C1.r + C2.r - d) == 0 || cmp(fabs(C1.r - C2.r) - d) == 0) {
        if(cmp(C2.r - C1.r) > 0) swap(C1, C2);
        res[0] = (C2.c - C1.c) / d * C1.r + C1.c;
        return 1;
    }

    double cost = (sqr(C1.r) + sqr(d) - sqr(C2.r)) / (2 * C1.r * d);
    double sint = sqrt(1.0 - sqr(cost));
    point p = (C2.c - C1.c) / d * C1.r;
    res[0] = C1.c + rotate_point(p, -sint, cost);
    res[1] = C1.c + rotate_point(p, sint, cost);
    return 2;
}




struct polygon_convex {
    vector<point> P;
    polygon_convex(int size = 0) {
        P.resize(size);
    }
    point& operator [](int index) {
        return P[index];
    }
    int size() {
        return P.size();
    }
};

bool comp_less(const point& a, const point& b) {
    return cmp(a.x - b.x) < 0 || cmp(a.x - b.x) == 0 && cmp(a.y - b.y) < 0;
}

polygon_convex convex_hull(vector<point>& a) {
    polygon_convex res(2 * a.size() + 5);
    sort(a.begin(), a.end(), comp_less);
    a.erase(unique(a.begin(), a.end()), a.end());
    int m = 0;
    for(int i = 0; i < a.size(); i++) {
        while(m > 1 && cmp(det(res[m - 1] - res[m - 2], a[i] - res[m - 2])) <= 0) m--;
        res[m++] = a[i];
    }
    int k = m;
    for(int i = int(a.size()) - 2; i >= 0; i--) {
        while(m > k && cmp(det(res[m - 1] - res[m - 2], a[i] - res[m - 2])) <= 0) m--;
        res[m++] = a[i];
    }
    res.P.resize(m);
    if(a.size() > 1) res.P.resize(m - 1);
    return res;
}



vector<point> Pin;
polygon_convex pc;
double S;
int n;

double sector_area(const point& a, const point& b, double r) {
    double A = angle(a) - angle(b);
    while(A <= 0) A += pi + pi;
    while(A >= pi + pi) A -= pi + pi;
    A = min(A, pi + pi - A);
    return sqr(r) * A / 2;
}

double Area(point& a, point& b, double& r) {
    int da = cmp(r - a.norm()) > 0;
    int db = cmp(r - b.norm()) > 0;
    double t1, t2;
    int num;
    circle cir(point(0.0, 0.0), r);
    point p[2];
    if(da && db) {
        return fabs(det(a, b)) * 0.5;
    }
    if(da && !db) {
        circle_cross_line(cir, line(a, b), t1, t2, p);
            if(cmp(t1) >= 0 && (t1 - 1) <= 0) {
                return sector_area(b, p[0], r) + fabs(det(a, p[0]) * 0.5);
            }
            return sector_area(b, p[1], r) + fabs(det(a, p[1]) * 0.5);           
        }

    if(!da && db) {
        circle_cross_line(cir, line(a, b), t1, t2, p);
            if(cmp(t1) >= 0 && cmp(t1 - 1) <= 0) {
                return sector_area(a, p[0], r) + fabs(det(b, p[0]) * 0.5);
            }
            return sector_area(a, p[1], r) + fabs(det(b, p[1]) * 0.5);
    }

    if(!da && !db) {
        if(circle_cross_line(cir, line(a, b), t1, t2, p) == 2) {
            if(cmp(t1) >= 0 && cmp(t1 - 1) <= 0 && cmp(t2) >= 0 && cmp(t2 - 1) <= 0) {
                return sector_area(a, p[0], r) + sector_area(p[1], b, r) + fabs(det(p[0], p[1])) * 0.5;
            }
        }
        return sector_area(a, b, r);
    }
    return 0;
}

double calc(double r) {
    double ret = 0;
    int n = pc.size();
    #define next(i) ((i + 1) % n)
    for(int i = 0; i < n; i++) {
        ret += Area(pc[i], pc[next(i)], r);
    }
    return ret;
}

int main() {
    int cas = 0;
    while(scanf("%d", &n) && n) {
        scanf("%lf", &S);
        Pin.resize(n);
        for(int i = 0; i < n; i++) Pin[i].input();
        pc = convex_hull(Pin);
        double l, r, mid, ans;
        l = 0;
        r = 100000.0;
        while(r - l >= 1e-4) {
            mid = (l + r) * 0.5;
            ans = calc(mid);
            if(ans < S) l = mid;
            else r = mid;
        }
        printf("Case %d: %.2f\n", ++cas, mid);
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值