• BZOJ2178 圆的面积并 计算几何 辛普森积分


    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ2178.html

    题目传送门 - BZOJ2178

    题意

      给出 $n(nleq 1000)$ 个圆,求面积并。

      所有圆的圆心坐标和半径都是绝对值不大于 1000 的整数。 

    题解

      自适应辛普森积分模板题。注意先删掉被其他圆包含的圆。

      但是 bzoj 大概是加过数据了,网上大部分直接自适应辛普森的代码都 TLE 了。

      有一种卡常方法效果很好:

      把 x 坐标按照整点划分成 $O(1000)$ 个区间,对于每一个区间,删除不涉及这个区间的所有圆。然后就过了。

     

    代码

    #include <bits/stdc++.h>
    #define y1 __zzd12323
    using namespace std;
    const int N=1005;
    const double Eps=1e-9,INF=1e9;
    double sqr(double x){
    	return x*x;
    }
    int n;
    struct Circle{
    	double x,y,r;
    }c[N],_c[N];
    bool cmpr(Circle a,Circle b){
    	return a.r>b.r;
    }
    struct Seg{
    	double L,R;
    }s[N];
    bool cmp(Seg a,Seg b){
    	return a.L<b.L;
    }
    double F(double x){
    	int m=0;
    	for (int i=1;i<=n;i++){
    		if (fabs(x-c[i].x)>c[i].r-Eps)
    			continue;
    		double M=c[i].y,a=sqrt(sqr(c[i].r)-sqr(x-c[i].x));
    		s[++m].L=M-a,s[m].R=M+a;
    	}
    	sort(s+1,s+m+1,cmp);
    	double res=0.0,mx=-INF;
    	for (int i=1;i<=m;i++)
    		if (s[i].L>mx)
    			res+=s[i].R-s[i].L,mx=s[i].R;
    		else if (s[i].R>mx)
    			res+=s[i].R-mx,mx=s[i].R;
    	return res;
    }
    double Simpson(double a,double b,double Fa,double Fb,double Fab){
    	return (b-a)/6*(Fa+Fab*4+Fb);
    }
    double Asr(double a,double b,double v,double Fa,double Fb,double Fab){
    	double ab=(a+b)/2;
    	double LFab=F((a+ab)/2),L=Simpson(a,ab,Fa,Fab,LFab);
    	double RFab=F((ab+b)/2),R=Simpson(ab,b,Fab,Fb,RFab);
    	if (fabs(v-L-R)<Eps)
    		return v;
    	return Asr(a,ab,L,Fa,Fab,LFab)
    	      +Asr(ab,b,R,Fab,Fb,RFab);
    }
    int killed[N];
    double Dis(double x1,double y1,double x2,double y2){
    	return sqrt(sqr(x1-x2)+sqr(y1-y2));
    }
    int main(){
    	scanf("%d",&n);
    	double a=INF,b=-INF;
    	for (int i=1;i<=n;i++){
    		scanf("%lf%lf%lf",&c[i].x,&c[i].y,&c[i].r);
    		a=min(a,c[i].x-c[i].r);
    		b=max(b,c[i].x+c[i].r);
    	}
    	sort(c+1,c+n+1,cmpr);
    	for (int i=1;i<=n;i++)
    		for (int j=i+1;j<=n;j++)
    			if (Dis(c[i].x,c[i].y,c[j].x,c[j].y)+c[j].r<c[i].r+Eps)
    				killed[j]=1;
    	int _n=0;
    	for (int i=1;i<=n;i++)
    		if (!killed[i])
    			c[++_n]=c[i];
    	n=_n;
    	double ans=0;
    	for (double x=a;x<b;x++){
    		for (int i=1;i<=n;i++)
    			_c[i]=c[i];
    		int _n=n;
    		n=0;
    		for (int i=1;i<=_n;i++)
    			if (c[i].x-c[i].r<i+1&&c[i].x+c[i].r>i)
    				c[++n]=_c[i];
    		n=_n;		
    		for (int i=1;i<=n;i++)
    			c[i]=_c[i];
    		double Fa=F(x),Fb=F(x+1),Fab=F((x+x+1)/2);
    		ans+=Asr(x,x+1,Simpson(x,x+1,Fa,Fb,Fab),Fa,Fb,Fab);
    	}
    	printf("%.3lf",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    配置PyDev,开始eclipsePython之旅
    PyDev下PyQt 的尝试
    逻辑回归 C++
    HP Unix vsftp服务配置
    线性回归(最小二乘法、批量梯度下降法、随机梯度下降法、局部加权线性回归) C++
    批量梯度下降(Batch gradient descent) C++
    利用expect验证主机口令
    python Paramiko 模块远程管理主机
    文件系统巡检
    awk查找特定字段
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ2178.html
Copyright © 2020-2023  润新知