Building Fence
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 171 Accepted Submission(s): 25
Special Judge
Problem Description Long long ago, there is a famous farmer named John. He owns a big farm and many cows. There are two kinds of cows on his farm, one is Friesian, and another one is Ayrshire. Each cow has its own territory. In detail, the territory of Friesian is a circle, and of Ayrshire is a triangle. It is obvious that each cow doesn’t want their territory violated by others, so the territories won’t intersect.
Since the winter is falling, FJ has to build a fence to protect all his cows from hungry wolves, making the territory of cows in the fence. Due to the financial crisis, FJ is currently lack of money, he wants the total length of the fence minimized. So he comes to you, the greatest programmer ever for help. Please note that the part of fence don’t have to be a straight line, it can be a curve if necessary.
Input The input contains several test cases, terminated by EOF. The number of test cases does not exceed 20.
Each test case begins with two integers N and M(0 ≤ N, M ≤ 50, N + M > 0)which denotes the number of the Friesian and Ayrshire respectively. Then follows N + M lines, each line representing the territory of the cow. Each of the first N lines contains three integers X
i, Y
i, R
i(1 ≤ R
i ≤ 500),denotes the coordinates of the circle’s centre and radius. Then each of the remaining M lines contains six integers X1
i, Y1
i, X2
i, Y2
i, X3
i, Y3
i, denotes the coordinates of the triangle vertices. The absolute value of the coordinates won’t exceed 10000.
Output For each test case, print a single line containing the minimal fence length. Your output should have an absolute error of at most 1e-3.
Sample Input 1 1 4 4 1 0 0 0 2 2 0
Sample Output 15.66692
Hint Please see the sample picture for more details, the fence is highlighted with red.
Source
2013 Multi-University Training Contest 7
Recommend zhuyuanchen520
标程的正解应该是找圆上的关键点。
两圆两两的切点,和三角形上的点和圆的切点是关键点。
然后所有点求凸包。
如果两个关键点刚好在一个圆上,用圆弧长度代替距离。
我的做法是没有求关键点,直接把圆均匀分成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 }