Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 171 Accepted Submission(s): 25
Special Judge
标程的正解应该是找圆上的关键点。
两圆两两的切点,和三角形上的点和圆的切点是关键点。
然后所有点求凸包。
如果两个关键点刚好在一个圆上,用圆弧长度代替距离。
我的做法是没有求关键点,直接把圆均匀分成1000个点,然后就水过了。
1 /* ********************************************** 2 Author : kuangbin 3 Created Time: 2013/8/13 14:13:06 4 File Name : F:\2013ACM练习\2013多校7\1002.cpp 5 *********************************************** */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 using namespace std; 19 20 const double eps = 1e-8; 21 const double PI = acos(-1.0); 22 int sgn(double x) 23 { 24 if(fabs(x) < eps)return 0; 25 if(x < 0)return -1; 26 else return 1; 27 } 28 struct Point 29 { 30 double x,y; 31 int index; 32 Point(){} 33 Point(double _x,double _y,int _index) 34 { 35 x = _x;y = _y;index = _index; 36 } 37 Point(double _x,double _y) 38 { 39 x = _x;y = _y; 40 } 41 Point operator -(const Point &b)const 42 { 43 return Point(x - b.x,y - b.y); 44 } 45 //叉积 46 double operator ^(const Point &b)const 47 { 48 return x*b.y - y*b.x; 49 } 50 //点积 51 double operator *(const Point &b)const 52 { 53 return x*b.x + y*b.y; 54 } 55 //绕原点旋转角度B(弧度值),后x,y的变化 56 void transXY(double B) 57 { 58 double tx = x,ty = y; 59 x = tx*cos(B) - ty*sin(B); 60 y = tx*sin(B) + ty*cos(B); 61 } 62 }; 63 64 //*两点间距离 65 double dist(Point a,Point b) 66 { 67 return sqrt((a-b)*(a-b)); 68 } 69 70 71 /* 72 * 求凸包,Graham算法 73 * 点的编号0~n-1 74 * 返回凸包结果Stack[0~top-1]为凸包的编号 75 */ 76 const int MAXN = 1010000; 77 Point list[MAXN]; 78 int Stack[MAXN],top; 79 //相对于list[0]的极角排序 80 bool _cmp(Point p1,Point p2) 81 { 82 double tmp = (p1-list[0])^(p2-list[0]); 83 if(sgn(tmp) > 0)return true; 84 else if(sgn(tmp) == 0 && sgn(dist(p1,list[0]) - dist(p2,list[0])) <= 0) 85 return true; 86 else return false; 87 } 88 void Graham(int n) 89 { 90 Point p0; 91 int k = 0; 92 p0 = list[0]; 93 //找最下边的一个点 94 for(int i = 1;i < n;i++) 95 { 96 if( (p0.y > list[i].y) || (p0.y == list[i].y && p0.x > list[i].x) ) 97 { 98 p0 = list[i]; 99 k = i; 100 } 101 } 102 swap(list[k],list[0]); 103 sort(list+1,list+n,_cmp); 104 if(n == 1) 105 { 106 top = 1; 107 Stack[0] = 0; 108 return; 109 } 110 if(n == 2) 111 { 112 top = 2; 113 Stack[0] = 0; 114 Stack[1] = 1; 115 return ; 116 } 117 Stack[0] = 0; 118 Stack[1] = 1; 119 top = 2; 120 for(int i = 2;i < n;i++) 121 { 122 while(top > 1 && sgn((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]])) <= 0) 123 top--; 124 Stack[top++] = i; 125 } 126 } 127 const int NUM = 500; 128 int X[100],Y[100],R[100]; 129 int main() 130 { 131 //freopen("in.txt","r",stdin); 132 //freopen("out.txt","w",stdout); 133 int N,M; 134 while(scanf("%d%d",&N,&M) == 2) 135 { 136 137 for(int i =0;i < N;i++) 138 { 139 scanf("%d%d%d",&X[i],&Y[i],&R[i]); 140 for(int j = 0;j < NUM;j++) 141 { 142 double tmp = 2*PI*j/NUM; 143 list[j+i*NUM] = Point( X[i] + R[i]*cos(tmp),Y[i] + R[i]*sin(tmp),i ); 144 } 145 146 } 147 int x,y; 148 for(int i = 0;i < M;i++) 149 { 150 scanf("%d%d",&x,&y); 151 list[N*NUM+i*3] = Point(x,y,-1); 152 scanf("%d%d",&x,&y); 153 list[N*NUM+i*3+1] = Point(x,y,-1); 154 scanf("%d%d",&x,&y); 155 list[N*NUM+i*3+2] = Point(x,y,-1); 156 } 157 Graham(N*NUM+M*3); 158 double ans = 0; 159 //cout<<top<<endl; 160 for(int i = 0;i < top;i++) 161 { 162 int t1 = Stack[i]; 163 int t2 = Stack[(i+1)%top]; 164 // cout<<t1<<" "<<t2<<endl; 165 // printf("%.2lf %.2lf\n",list[t1].x,list[t2].y); 166 if(list[t1].index != -1 && list[t2].index == list[t1].index) 167 { 168 int tt = list[t1].index; 169 ans += R[tt]*2*PI/(NUM); 170 } 171 else ans += dist(list[t1],list[t2]); 172 } 173 printf("%.5lf\n",ans); 174 } 175 return 0; 176 }