1 /*
2 LA4127计算几何
3 离散化的思想。刘的书上已经说得很清楚。
4 重点是自己手写的函数:
5 1、判断线段和线段的交点
6 2、覆盖在最上面的线段的判断
7 离散化的思想和之前做的LA2527是一致的
8 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <math.h>
13 #include <ctype.h>
14 #include <string>
15 #include <iostream>
16 #include <sstream>
17 #include <vector>
18 #include <queue>
19 #include <stack>
20 #include <map>
21 #include <list>
22 #include <set>
23 #include <algorithm>
24 #define INF 0x3f3f3f3f
25 #define eps 1e-7
26 #define eps2 1e-3
27 #define zero(x) (((x)>0?(x):-(x))<eps)
28 using namespace std;
29
30
31 struct Point
32 {
33 double x,y;
34 Point() {}
35 Point(double xx,double yy)
36 {
37 x=xx;
38 y=yy;
39 }
40 bool operator<(const Point& p) const{
41 if (x==p.x) return y<p.y;
42 else return x<p.x;
43 }
44 };
45
46 typedef Point Vector;
47
48 struct Segment
49 {
50 Point p1,p2;
51 Segment(){}
52 Segment(Point p11,Point p22)
53 {
54 p1=p11;p2=p22;
55 }
56 double getk()
57 {
58 return (p1.y-p2.y)/(p1.x-p2.x);
59 }
60 }Seg[25005];
61
62 struct Line
63 {
64 Point p;
65 Vector v;
66 Line(){}
67 Line(Point pp,Vector vv)
68 {
69 v=vv;
70 p=pp;
71 }
72 };
73 bool operator==(Point A,Point B)
74 {
75 if ((fabs(A.x-B.x)<eps) && (fabs(A.y-B.y)<eps)) return true;
76 else return false;
77 }
78 Vector operator-(Point A,Point B)//表示A指向B
79 {
80 return Vector(A.x-B.x,A.y-B.y);
81 }
82 Vector operator*(Vector A,double k)
83 {
84 return Vector(A.x*k,A.y*k);
85 }
86 Vector operator+(Point A,Point B)//表示A指向B
87 {
88 return Vector(B.x+A.x,B.y+A.y);
89 }
90 double Dot(Vector A,Vector B)
91 {
92 return A.x*B.x+A.y*B.y;
93 }
94 double Length(Vector A)
95 {
96 return sqrt(Dot(A,A));
97 }
98 double Cross(Vector A,Vector B)
99 {
100 return A.x*B.y-A.y*B.x;
101 }
102 double Area2(Point A,Point B,Point C)
103 {
104 return Cross(B-A,C-A);
105 }
106 int dcmp(double x)
107 {
108 if(fabs(x)<eps) return 0;
109 else if(x>0) return 1;
110 else return -1;
111 }
112 double angle(Vector v)
113 {
114 return atan2(v.y,v.x);
115 }
116 Vector Rotate(Vector A,double rad)//向量向逆时针旋转
117 {
118 return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
119 }
120 Point InterSection(Line L1,Line L2)//求直线交点
121 {
122 Vector u=L1.p-L2.p;
123 double t=Cross(L2.v,u)/Cross(L1.v,L2.v);
124 return L1.p+L1.v*t;
125 }
126 bool SegInter(Segment l1,Segment l2,double* xx)
127 {
128 Point jiao=(InterSection(Line(l1.p1,l1.p2-l1.p1),Line(l2.p1,l2.p2-l2.p1)));
129 *xx=jiao.x;
130 if ( *xx-l1.p1.x>=0 && l1.p2.x-*xx>=0 && *xx-l2.p1.x>=0 && l2.p2.x-*xx>=0) return true;else return false;
131 }
132 int findUpesetLine(int cnt,double a)//线段个数,中点横坐标,返回最上(后)覆盖这个点的线段序号
133 {
134 int ans=-1;
135 double my=-1;
136 for(int i=0;i<cnt;i++)
137 {
138 double x1=Seg[i].p1.x,y1=Seg[i].p1.y,x2=Seg[i].p2.x,y2=Seg[i].p2.y;
139 if (x1-a>0 || a-x2>0) continue;
140 double k1=x1-a,k2=x2-a;
141 double y=(k2*y1-k1*y2)/(-k1+k2);
142 if (y-my>0)
143 {
144 my=y;
145 ans=i;
146 }
147 }
148 return ans;
149 }
150 int n,cas=0;
151 double x,h,b;
152 double X[25500];//离散的x坐标
153 int main()
154 {
155 double ans=0;
156 int cnt=0;//线段的个数
157 int cnt2=0;//离散点的个数
158 while(cin>>n && n>0)
159 {
160 cas++;
161 ans=0;
162 cnt=cnt2=0;
163 for(int i=0;i<n;i++)//预处理
164 {
165 cin>>x>>h>>b;
166 b=b/2;
167 Seg[cnt++]=Segment(Point(x-b,0),Point(x,h));
168 Seg[cnt++]=Segment(Point(x,h),Point(x+b,0));
169 X[cnt2++]=x-b;X[cnt2++]=x;X[cnt2++]=x+b;
170 }
171 for(int i=1;i<cnt;i++)
172 for(int j=0;j<i;j++)//线段两两求交点
173 {
174 double xx;
175 bool ok=SegInter(Seg[i],Seg[j],&xx);
176 if (ok) X[cnt2++]=xx;
177 }
178 sort(X,X+cnt2);
179 // for(int i=0;i<cnt2;i++) cout<<X[i]<<" ";cout<<endl;
180 for(int i=0;i<cnt2-1;i++)//枚举每两个相邻离散线段的中点
181 {
182 double px=(X[i]+X[i+1])/2;
183 int num=findUpesetLine(cnt,px);
184 if (num!=-1){
185 double k=Seg[num].getk();//用斜率求线段长度
186 ans+=(X[i+1]-X[i])*sqrt(1+k*k);
187 }
188 }
189 printf("Case %d: %d\n\n",cas,(int)(ans+0.5));
190 }
191
192 }