原题地址:http://codeforces.com/problemset/problem/814/D
题意:给定
的圆(任意两个圆的交点都不超过
个),现在要求将这些圆划为两部分,使得被覆盖奇数次圆的面积和减去被覆盖偶数次圆的面积最大。
思路:考虑一下贪心策略.
首先如果一个圆和任意一个其他的圆都是不相交的,那么他的面积肯定是要被算进去的.
那么题目又说要将圆分成两个部分,那么如果一个圆被另一个大圆覆盖了,那么把这个圆拖到另一个集合里面,这样子他的面积也能够得到.但是如果一个圆被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;
}