1043: [HAOI2008]下落的圆盘
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1656 Solved: 704
[Submit][Status][Discuss]
Description
有n个圆盘从天而降,后面落下的可以盖住前面的。求最后形成的封闭区域的周长。看下面这副图, 所有的红
色线条的总长度即为所求.
Input
第一行为1个整数n,N<=1000
接下来n行每行3个实数,ri,xi,yi,表示下落时第i个圆盘的半径和圆心坐标.
Output
最后的周长,保留三位小数
Sample Input
2
1 0 0
1 1 0
1 0 0
1 1 0
Sample Output
10.472
写这道题让我领悟了一个道理
计几题不要算复杂度 先想出怎么做再说...
n^2的算法很显然 枚举每一个被它压在身下的圆
看它覆盖掉了多大弧度
具体来讲 知道圆心距 两半径 即可用余弦定理求角度
注意判两个圆没有焦点的情况
#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef double db;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}
const int N=1010;
const db pi=acos(-1),eps=1e-8;
struct point
{
db x,y;
friend point operator +(const point &a,const point &b)
{return (point){a.x+b.x,a.y+b.y};}
friend point operator -(const point &a,const point &b)
{return (point){a.x-b.x,a.y-b.y};}
friend db dot(const point &a,const point &b)
{return a.x*b.x+a.y*b.y;}
friend db dis(const point &a,const point &b)
{return sqrt(dot(a-b,a-b));}
};
struct circle
{
db r;point o;
friend bool in(const circle &a,const circle &b)
{return a.r+dis(a.o,b.o)<b.r+eps;}
friend bool out(const circle &a,const circle &b)
{return a.r+b.r<dis(a.o,b.o)+eps || dis(a.o,b.o)+b.r<a.r+eps;}
}c[N];
struct arc
{
db fr,to;
friend bool operator <(const arc &a,const arc &b)
{return a.fr<b.fr;}
}a[N][N<<1];
int num[N];
void get_insert(int v,int u)
{
db d=dis(c[u].o,c[v].o);
db theta=acos((c[v].r*c[v].r+d*d-c[u].r*c[u].r)/(2*d*c[v].r));
db alpha=atan2(c[u].o.y-c[v].o.y,c[u].o.x-c[v].o.x);
if(alpha<0) alpha+=2*pi;
alpha-=theta;theta=alpha+theta*2;
if(alpha<0) alpha+=2*pi;
if(theta>2*pi) theta-=2*pi;
if(theta<alpha)
{
a[v][++num[v]]=(arc){alpha,2*pi};
a[v][++num[v]]=(arc){0,theta};
}
else a[v][++num[v]]=(arc){alpha,theta};
}
bool covered[N];
int main()
{
int n=read();
register int i,j;
for(i=1;i<=n;++i)
scanf("%lf%lf%lf",&c[i].r,&c[i].o.x,&c[i].o.y);
for(i=2;i<=n;++i)
for(j=1;j<i;++j)
if(!covered[j])
{
if(in(c[j],c[i]))
{covered[j]=1;continue;}
if(out(c[j],c[i])) continue;
get_insert(j,i);
}
db ans(0);
for(i=1;i<=n;++i)
if(!covered[i])
{
sort(a[i]+1,a[i]+num[i]+1);
db remain=2*pi-a[i][1].to+a[i][1].fr,tail=a[i][1].to;
for(j=2;j<=num[i];++j)
{
remain-=a[i][j].to-a[i][j].fr,
remain+=max(min(tail,a[i][j].to)-a[i][j].fr,0.0),
tail=max(tail,a[i][j].to);
}
ans+=remain*c[i].r;
}
printf("%.3lf\n",ans);
return 0;
}