题目链接:http://codeforces.com/contest/814/problem/D
题意:有n个人跳舞,然后每个人跳舞的区域是一个圆,圆与圆不想交。然后现在把这些人分成白天和黑夜跳舞的两批。如果一个人跳舞被覆盖奇数次,他的面积就需要被减去,被覆盖偶数次他的面积就会被加上,然后现在问你跳舞合适的最大面积是多少。
分析:英语不好,题意看了好久才懂,其实将道理这道题跟着题意走就行了。首先需要确定每个圆与其他圆之间的关系,是否被覆盖,即包含。覆盖奇数次加上,偶数次减去,那么我肯定尽量加上大圆,减去小圆。我们可以记录每个圆可以覆盖的圆入队列,并且记录可以覆盖每个圆的最小圆是谁。对于一个大圆,他所包含的所有圆构成的面积最大就是他的面积加上奇数覆盖的面积-偶数覆盖圆的面积。可以bfs求,然后只有直接覆盖某个圆的时候才可以入队列。圆面积按大小排序,然后i如果覆盖j,g[i].push_back(j),然后枚举1到n各个圆,bfs,如果面积已经被计算过,return0,求和即可。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 struct st{ 5 long long x,y,r; 6 int id,cnt; 7 }a[1005]; 8 vector<st>g[1005]; 9 int d[1005]; 10 double pi=3.1415926535898; 11 int vis[1005]; 12 13 long long bfs(int x){ 14 queue<st >q; 15 if(vis[x]==1) return 0; 16 q.push(a[x]); 17 vis[x]=1; 18 long long sum=a[x].r*a[x].r; 19 while(!q.empty()){ 20 st b=q.front(); 21 q.pop(); 22 int l=g[b.id].size(); 23 for(int i=0;i<l;i++){ 24 if(d[g[b.id][i].id]==b.id){ 25 g[b.id][i].cnt=b.cnt+1; 26 vis[g[b.id][i].id]=1; 27 if(g[b.id][i].cnt%2==1) sum+=g[b.id][i].r*g[b.id][i].r; 28 else sum-=g[b.id][i].r*g[b.id][i].r; 29 q.push(g[b.id][i]); 30 } 31 } 32 } 33 return sum; 34 } 35 bool cmp(st a,st b){ 36 return a.r>b.r; 37 } 38 int main(){ 39 int n; 40 cin>>n; 41 int x,y,r; 42 for(int i=1;i<=n;i++){ 43 cin>>a[i].x>>a[i].y>>a[i].r; 44 } 45 memset(d,0,sizeof(d)); 46 sort(a+1,a+1+n,cmp); 47 for(int i=1;i<=n;i++){ 48 a[i].id=i; 49 a[i].cnt=0; 50 } 51 for(int i=1;i<=n;i++){ 52 for(int j=i+1;j<=n;j++){ 53 if(((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y))<(a[i].r+a[j].r)*(a[i].r+a[j].r)){ 54 g[i].push_back(a[j]); 55 d[j]=i; 56 } 57 } 58 } 59 memset(vis,0,sizeof(vis)); 60 long long result=0; 61 for(int i=1;i<=n;i++){ 62 result+=bfs(i); 63 } 64 printf("%.8lf ",pi*result); 65 return 0; 66 }