D. An overnight dance in discotheque Codeforces Round #418 (Div. 2) (贪心)

原题地址:http://codeforces.com/problemset/problem/814/D
题意:给定 n 的圆(任意两个圆的交点都不超过 1 个),现在要求将这些圆划为两部分,使得被覆盖奇数次圆的面积和减去被覆盖偶数次圆的面积最大。

思路:考虑一下贪心策略.
首先如果一个圆和任意一个其他的圆都是不相交的,那么他的面积肯定是要被算进去的.
那么题目又说要将圆分成两个部分,那么如果一个圆被另一个大圆覆盖了,那么把这个圆拖到另一个集合里面,这样子他的面积也能够得到.但是如果一个圆被2个大圆覆盖,那么他的面积无论如何都是不可能被计算进去的,(因为要想使两个集合的圆的面积最大,那么必然是从大的圆开始考虑),所以我们就可以得到解题方法,为每一圆设立一个参数num,那么每被大圆被盖一次,就num++,到最后如果num==0(没有被任何一个覆盖)或者num是奇数就加上面积,反之就减.

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 5;
const double pi = acos(-1.0);
struct node {
    int  x, y, r;
    int num;
    double area;
} a[maxn];
int n;
bool cmp(node a, node b) {
    return a.r > b.r;
}
bool in(node a, node b) {
    return 1.0 * (a.x - b.x) * (a.x - b.x) + 1.0 * (a.y - b.y) * (a.y - b.y) < 1.0 * (a.r + b.r) * (a.r + b.r);
}

int main() {
    while(cin >> n) {
        for(int i = 1; i <= n; i++) {
            scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].r);
            a[i].area = pi * a[i].r * a[i].r;
        }
        sort(a + 1, a + 1 + n, cmp);
        for(int i = 1; i <= n; i++) {
            for(int j = i + 1; j <= n; j++) {
                if(in(a[i], a[j]))
                    a[j].num++;
            }
        }
        double ans = 0.0;
        for(int i = 1; i <= n; i++) {
            if(!a[i].num || a[i].num % 2) ans += a[i].area;
            else ans -= a[i].area;
        }
        printf("%.8f\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81428708