1. 程式人生 > >[HAOI2008]下落的圓盤

[HAOI2008]下落的圓盤

利用 ostream namespace lin class eof cst ont 暴力

直接暴力O(n^2)枚舉 每一個圓盤和其後面落下的圓盤

i 當前枚舉的圓 j i之後的圓

然後利用atan2函數求出(x[j]-x[i],y[j]-y[i])向量與x軸的夾角

再根據d(圓心之間距離)、r[i]、r[j]余弦定理求出向量可以向上下擴展的角度

用貪心線段覆蓋...

枚舉的時候有幾種特殊情況:

1.兩個圓相離

2.i在j內

3.j在i內

4.斜率不存在的情況不用考慮,atan2函數就行了

技術分享
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include 
<iostream> #include <cmath> #define mem(a,b) memset(a,b,sizeof(a)) #define ll long long #define dd double using namespace std; const int N=1006; const dd pai=acos(-1.0); struct son { dd l,r; bool friend operator < (son a,son b) { if(a.l==b.l) return a.r<b.r;
return a.l<b.l; } }ji[N*10]; int con; int n; dd r[N],x[N],y[N]; inline dd dis(dd x3,dd y3,dd x4,dd y4) { return sqrt( (x4-x3)*(x4-x3)+(y4-y3)*(y4-y3) ); } dd check() { sort(ji+1,ji+1+con); dd ans=0,las=-pai; for(int i=1;i<=con;++i) { if(ji[i].l<las) {
if(ji[i].r>las) ans+=(ji[i].r-las); } else { ans+=(ji[i].r-ji[i].l); } if(las<ji[i].r) las=ji[i].r; } return ans; } dd work() { dd ce1,ce2,d,ans=0,temp,sh,xi; for(int i=1;i<=n;++i) { con=0; for(int j=i+1;j<=n;++j) { d=dis(x[i],y[i],x[j],y[j]); if(d>r[i]+r[j])//i和j相離 continue; if(d+r[i]<r[j])//i整個被覆蓋 { ji[++con]=(son){-pai,pai}; break; } if(d+r[j]<r[i])//j在i中間 continue; /*if(x[j]==x[i]) ce1=(y[j]-y[i]>0?pai/2.0:-pai/2.0);//直角 .... (還是別判斷了...容易wa) else*/ ce1=atan2( (x[j]-x[i]),(y[j]-y[i]) ); ce2=acos( (r[i]*r[i]+d*d-r[j]*r[j])/(2*r[i]*d) ); sh=ce1+ce2;xi=ce1-ce2; if(sh>pai) ji[++con]=(son){ -pai,sh-2*pai },sh=pai; if(xi<-pai) ji[++con]=(son){ xi+2*pai,pai },xi=-pai; ji[++con]=(son){ xi,sh }; } temp=check(); //printf("temp=%lf\n",temp); ans+=((2.0*pai-temp)*r[i]); } return ans; } int main(){ //freopen("in.in","r",stdin); //freopen("disc.in","r",stdin); //freopen("disc.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%lf%lf%lf",&r[i],&x[i],&y[i]); printf("%.3lf",work()); }
下落的圓盤

[HAOI2008]下落的圓盤