题目描述
大厨非常擅长烹饪,他做的菜是城镇最好的,因此他打算装饰一下他的餐厅。顾客到店第一眼看到的是餐厅的门,所以大厨想从装饰门开始。他昨晚已经想出了一个新的设计,从门上挖去一些圆形,再在这些位置装上玻璃,让玻璃形成奇特的形状。
形式上,我们可以将大厨的一系列过程抽象为以下过程。令门为一个坐标平面上以 (0,0),(W,0),(0,H),(W,H) 为四角的矩形。一开始门是白色的,而坐标平面其他部分是黑色的。每一步大厨会将一个圆的内部涂黑。在他涂完所有圆之后,他将门内的黑色部分(在代表门的矩形内的黑色部分)挖掉,并装上玻璃。
门的奇特程度可以用窗户在门内的边界的周长表示(请参考样例中第二组数据理解)。大厨在涂色之后已经很疲惫了,他请你算出这个数。
输入格式
第一行一个整数 T,表示数据组数。下面是 T 组测试数据。
每组数据第一行有三个整数 W,H,N,代表门的尺寸和圆的数量。
下面 N 行描述 N 个圆,第 i 行有三个实数 X,Y,R,每个数恰好保留了两位小数,表示大厨第 i 步挖掉的圆的圆心坐标和半径。
输出格式
对于每组测试数据,输出一行表示问题描述中所指的窗户周长之和。(四舍五入保留 5 位小数)
样例
input
2 8 10 8 2.00 2.00 1.00 4.00 2.00 0.50 6.00 2.00 1.00 4.00 5.00 1.50 3.00 6.00 0.50 3.00 7.00 0.75 5.00 7.00 1.00 4.00 8.00 1.00 7 7 3 1.00 1.00 2.00 3.00 3.00 1.50 6.00 5.00 1.50
output
33.64043 17.20584
explanation
第一组数据:答案是下图中粗线的长度总和
第二组数据:答案是下图中粗线的长度总和
限制与约定
对于 10% 的数据,N≤1。
对于 30% 的数据,N≤2。
对于另外 50% 数据,所有圆不与矩形相交。
对于 60% 的数据,N≤100。
对于 100% 的数据,1≤N,T,W,H≤1000,0<R≤1000,0≤X,Y≤1000。
在输入中 N 的和不超过 5000。
X,Y,R 均恰好保留两位小数。
所有圆都是不同的,任意两个圆要么圆心不同,要么半径不同。
时间限制:1s
空间限制:256MB
========================================华丽丽的分割线======================================
这是一个集训的题目,基础计算几何吧。
由于n只有5000,考虑每个圆对答案的贡献度。
对于每一个圆,枚举和它相交的圆,于是我们可以得到很多pair,每个pair记录被遮住的部分。
然后每个圆,和四条直线分别判断一下。
让我WA哭的细节在于,一个pair本质意义是所有部分全部遮住,但是会被判断成只遮住了一个点,所以这个情况需要特判。
然后对于每一个圆,把所有的pair排序一下扫一遍就可以统计答案了。
震惊!这题std没有eps!
时间复杂度O(n^2logn),代码如下:
1 #include <bits/stdc++.h> 2 #define Maxn 6007 3 #define double long double 4 #define abs fabsl 5 using namespace std; 6 int read() 7 { 8 int x=0,f=1;char ch=getchar(); 9 while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} 10 while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 11 return x*f; 12 } 13 int T,n; 14 double H,W; 15 double x[Maxn],y[Maxn],r[Maxn]; 16 pair<double,double> s[Maxn*2]; 17 double alpha1,alpha2,alpha,p,q; 18 double a,b,c; 19 double ans; 20 double arccos(double x) 21 { 22 if (x<-1.0) x=-1.0; 23 if (x>1.0) x=1.0; 24 return (double)acosl(x); 25 } 26 int main() 27 { 28 T=read(); 29 while (T--) 30 { 31 W=1.0*read(),H=1.0*read(),n=read(); 32 for (int i=1;i<=n;i++) 33 scanf("%Lf%Lf%Lf",&x[i],&y[i],&r[i]); 34 ans=0.0; 35 for (int i=1;i<=n;i++) 36 { 37 int cnt=0; 38 memset(s,0,sizeof(s)); 39 for (int j=1;j<=n;j++) 40 if (j!=i) 41 { 42 alpha1=atan2l(1.0*(y[j]-y[i]),1.0*(x[j]-x[i])); 43 a=(double)sqrtl(1.0*(y[j]-y[i])*(y[j]-y[i])+1.0*(x[j]-x[i])*(x[j]-x[i])); 44 b=1.0*r[i],c=1.0*r[j]; 45 if (a>=b+c) continue; 46 alpha2=arccos((double)((1.0*a*a+1.0*b*b-1.0*c*c))/(2.0*a*b)); 47 p=alpha1-alpha2,q=alpha1+alpha2; 48 if (abs(b-c)>a&&r[i]<r[j]) p=0.0,q=2*M_PI; 49 if (p<0) p+=2*M_PI; 50 if (q<0) q+=2*M_PI; 51 if (p>=2*M_PI) p-=2*M_PI; 52 if (q>=2*M_PI) q-=2*M_PI; 53 if (alpha2>=M_PI) p=0.0,q=2*M_PI; 54 if (p<=q) s[++cnt]=make_pair(p,q); 55 else 56 { 57 s[++cnt]=make_pair(p,2*M_PI); 58 s[++cnt]=make_pair(0.0,q); 59 } 60 } 61 if (y[i]-r[i]<0) 62 { 63 alpha=arccos((double)(y[i])/(r[i])); 64 p=1.5*M_PI-alpha,q=1.5*M_PI+alpha; 65 if (p<0) p+=2*M_PI; 66 if (q<0) q+=2*M_PI; 67 if (p>=2*M_PI) p-=2*M_PI; 68 if (q>=2*M_PI) q-=2*M_PI; 69 if (alpha>=M_PI) p=0.0,q=2*M_PI; 70 if (p<=q) s[++cnt]=make_pair(p,q); 71 else 72 { 73 s[++cnt]=make_pair(p,2*M_PI); 74 s[++cnt]=make_pair(0.0,q); 75 } 76 } 77 if (y[i]+r[i]>H) 78 { 79 alpha=arccos((double)((H-y[i])/(r[i]))); 80 p=0.5*M_PI-alpha,q=0.5*M_PI+alpha; 81 if (p<0) p+=2*M_PI; 82 if (q<0) q+=2*M_PI; 83 if (p>=2*M_PI) p-=2*M_PI; 84 if (q>=2*M_PI) q-=2*M_PI; 85 if (alpha>=M_PI) p=0.0,q=2*M_PI; 86 if (p<=q) s[++cnt]=make_pair(p,q); 87 else 88 { 89 s[++cnt]=make_pair(p,2*M_PI); 90 s[++cnt]=make_pair(0.0,q); 91 } 92 } 93 if (x[i]-r[i]<0) 94 { 95 alpha=arccos((double)(x[i])/(r[i])); 96 p=M_PI-alpha,q=M_PI+alpha; 97 if (p<0) p+=2*M_PI; 98 if (q<0) q+=2*M_PI; 99 if (p>=2*M_PI) p-=2*M_PI; 100 if (q>=2*M_PI) q-=2*M_PI; 101 if (alpha>=M_PI) p=0.0,q=2*M_PI; 102 if (p<=q) s[++cnt]=make_pair(p,q); 103 else 104 { 105 s[++cnt]=make_pair(p,2*M_PI); 106 s[++cnt]=make_pair(0.0,q); 107 } 108 } 109 if (x[i]+r[i]>W) 110 { 111 alpha=arccos((double)((W-x[i]))/(r[i])); 112 p=2*M_PI-alpha,q=alpha; 113 if (p<0) p+=2*M_PI; 114 if (q<0) q+=2*M_PI; 115 if (p>=2*M_PI) p-=2*M_PI; 116 if (q>=2*M_PI) q-=2*M_PI; 117 if (alpha>=M_PI) p=0.0,q=2*M_PI; 118 if (p<=q) s[++cnt]=make_pair(p,q); 119 else 120 { 121 s[++cnt]=make_pair(p,2*M_PI); 122 s[++cnt]=make_pair(0.0,q); 123 } 124 } 125 sort(s+1,s+cnt+1); 126 double del=0.0,rmax=0.0; 127 del+=s[1].first; 128 rmax=s[1].second; 129 for (int j=2;j<=cnt;j++) 130 { 131 if (s[j].first>rmax) del+=(s[j].first-rmax); 132 rmax=max(rmax,s[j].second); 133 } 134 if (2*M_PI>rmax) del+=(2*M_PI-rmax); 135 ans+=r[i]*del; 136 } 137 printf("%.5Lf ",ans); 138 } 139 return 0; 140 }