2017-2018 Northwestern European Regional Contest (NWERC 2017) G - Glyph Recognition (二分)

题目链接:http://codeforces.com/gym/101623

题目大意:二维平面内有n个点。现在要你找出两个满足如下条件的正k边形(3<=k<=8)

1、平面内的 n 个点全部在大的正k边形内;

2、小的正k边形嵌套在大的正k边形内,同时没有一个点在小的正k边形内,或者在k边形上;

3、这两个k边形的中心都在原点(0,0);

4、两个正k边形都有一个顶点在x轴的正半轴上。

现在令val = S(小正k边形)/ S(大正k边形)。(S指面积)要你求出最大的val值,同时输出k。

题目思路:由于k的范围很小,所以我们可以考虑直接枚举是几边形进行覆盖,求出所有的val值,最后再取最大值。

对于当前是 k 边形的时候,我们考虑可以用二分正多边形的半径 r (顶点到中心的距离)来求出满足条件时的大小多边形,然后再求出这两个多边形的面积,进行比值即可。

具体实现看代码:

#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define lowbit(x) x&-x
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define IOS ios::sync_with_stdio(false)
#define fuck(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
typedef pair<ll, ll>pll;
const int MX = 1000 + 5;
const double pi = acos(-1.0);
const double eps = 1e-8;

int n;
struct Point {
    double x, y;
    Point() {}
    Point(double x, double y): x(x), y(y) {}
};
Point operator-(Point A, Point B) {return Point(A.x - B.x, A.y - B.y);}
double sqr(double x) {return x * x;}
int dcmp(double x) {
    if (fabs(x) < eps) return 0;
    return x < 0 ? -1 : 1;
}
double Cross(Point A, Point B) {
    return A.x * B.y - A.y * B.x;
}
double Dot(Point A, Point B) {
    return A.x * B.x + A.y * B.y;
}
double dist(Point A, Point B) {
    return sqrt(sqr(A.x - B.x) + sqr(A.y - B.y));
}
Point Rotate(Point A, double ang) {
    return Point(A.x * cos(ang) - A.y * sin(ang), A.x * sin(ang) - A.y * cos(ang));
}
Point p[MX];
bool is_on_Segment(Point A, Point s, Point t) {
    return dcmp(Cross(s - A, s - t)) == 0 && dcmp(Dot(s - A, t - A)) <= 0;
}
struct Polygon {
    int n;
    Point a[MX];

    double get_area() {
        double sum = 0;
        a[n + 1] = a[1];
        for (int i = 1; i <= n; ++i) sum += Cross(a[i + 1], a[i]);
        return sum / 2;
    }
    int is_in_polygon(Point pp) {
        int num = 0;
        a[n + 1] = a[1];
        for (int i = 1; i <= n; ++i) {
            if (is_on_Segment(pp, a[i], a[i + 1])) return 2;
            int s = dcmp(Cross(a[i] - a[i + 1], a[i] - pp));
            int s1 = dcmp(a[i].y - pp.y);
            int s2 = dcmp(a[i + 1].y - pp.y);
            if (s > 0 && s1 <= 0 && s2 > 0) num++;
            if (s < 0 && s1 > 0 && s2 <= 0) num--;
        }
        return num != 0;
    }
};

Polygon make_polygon(int n, double r) {
    Polygon A;
    double ang = pi * 2 / n;
    A.n = n;
    A.a[1] = Point(r, 0);
    for (int i = 2; i <= n; ++i)
        A.a[i] = Rotate(A.a[1], pi * 2 - ang * (i - 1));
    return A;
}
bool check1(Polygon A) {
    for (int i = 1; i <= n; ++i)
        if (A.is_in_polygon(p[i]) == 0) return 0;
    return 1;
}
bool check2(Polygon A) {
    for (int i = 1; i <= n; ++i)
        if (A.is_in_polygon(p[i]) == 1) return 0;
    return 1;
}

int main() {
    //FIN;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        scanf("%lf%lf", &p[i].x, &p[i].y);
    double ans = 0;
    int id = 0;
    Polygon A;
    for (int i = 3; i <= 8; ++i) {
        double l = 0, r = 1e9, out_area = 0, in_area = 0;
        while (r - l > eps) {
            double mid = (l + r) / 2;
            A = make_polygon(i, mid);
            if (check1(A)) r = mid;
            else l = mid;
        }
        A = make_polygon(i, l);
        out_area = A.get_area();
        l = 0 , r = 1e9;
        while (r - l > eps) {
            double mid = (l + r) / 2;
            A = make_polygon(i, mid);
            if (check2(A)) l = mid;
            else r = mid;
        }
        A = make_polygon(i, l);
        in_area = A.get_area();
        double res = in_area / out_area;
        if (res > ans) {
            ans = res;
            id = i;
        }
    }
    printf("%d %.10f\n", id, ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Lee_w_j__/article/details/83548592