HDU 4667 Building Fence(2013多校7 1002题 计算几何,凸包,圆和三角形)

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.
HDU 4667 Building Fence(2013多校7 1002题 计算几何,凸包,圆和三角形)
 

 

Source
 

 

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 }

 

 

 

 

 

 

 

你可能感兴趣的:(Build)