这个题的DP做法感觉好神奇...

容易发现圆的包含关系是一个森林,我们设计状态是F[i][0/1][0/1]表示以i为根的子树中,第一个集合有偶数/奇数个圆包含它,第二个集合有偶数/奇数个圆包含它时能取得的最大权值,那么我们就可以比较容易的转移了。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<vector>
 6 using namespace std;
 7 #define maxn 1005
 8 typedef long long LL;
 9 struct Vergil
10 {
11     int x,y,r;    
12 }t[maxn];
13 int n,father[maxn];
14 LL f[maxn][2][2],ans;
15 vector<int> son[maxn];
16 
17 LL dist(int o1,int o2) 
18 {
19     return (LL)(t[o1].x-t[o2].x)*(t[o1].x-t[o2].x)+(LL)(t[o1].y-t[o2].y)*(t[o1].y-t[o2].y);    
20 }
21 
22 inline bool bh(int o1,int o2) 
23 {
24     return dist(o1,o2)<(LL)t[o1].r*t[o1].r;    
25 }
26 
27 void dfs(int u) 
28 {
29     int siz=son[u].size();
30     LL g[2][2]={{0}};
31     for (int i=0;i<siz;i++)  
32     {
33         int v=son[u][i];
34         dfs(v);
35         for (int j=0;j<2;j++)
36             for (int k=0;k<2;k++) 
37                 g[j][k]+=f[v][j][k];
38     }
39     LL w=(LL)t[u].r*t[u].r;
40     for (int i=0;i<2;i++)
41         for (int j=0;j<2;j++)
42             f[u][i][j]=max(g[i^1][j]+w*(i==0?1:-1),g[i][j^1]+w*(j==0?1:-1));
43 }
44 
45 int main()
46 {
47     scanf("%d",&n);
48     for (int i=1;i<=n;i++) scanf("%d%d%d",&t[i].x,&t[i].y,&t[i].r);
49     for (int i=1;i<=n;i++)
50         for (int j=1;j<=n;j++) 
51         {
52             if (t[j].r<=t[i].r) continue;
53             if (!bh(j,i)) continue;
54             if (!father[i]||t[father[i]].r>t[j].r) father[i]=j;
55         }
56     for (int i=1;i<=n;i++) 
57         if (father[i]) son[father[i]].push_back(i);
58     for (int i=1;i<=n;i++)
59         if (!father[i]) 
60         {
61             dfs(i);
62             ans+=f[i][0][0];
63         }
64     printf("%.10f\n",ans*acos(-1));
65     return 0;    
66 }

 

posted on 2017-06-08 19:00  Vergil_LY  阅读(214)  评论(0编辑  收藏  举报