[HAOI2008]下落的圆盘
Posted A_LEAF
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HAOI2008]下落的圆盘相关的知识,希望对你有一定的参考价值。
直接暴力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]下落的圆盘的主要内容,如果未能解决你的问题,请参考以下文章