zoukankan      html  css  js  c++  java
  • 计算几何 val.3

    计算几何 val.3

    自适应辛普森法

    可以用来求多边形的面积并(圆也行)

    定积分

    定积分的几何意义是函数的曲线上 (x) 的一段区间与 (x) 轴围成的曲边梯形的带符号面积

    表示法为

    [int_{a}^{b} f(x) mathrm{d} x ]

    引入

    计算方法:

    1. 分成一堆小区间

      [int_{a}^{b} f(x) mathrm{d} x=lim _{n ightarrow infty} sum_{i=1}^{n} frac{b-a}{n} fleft(a+frac{b-a}{n} i ight) ]

    2. 牛顿-莱布尼茨公式

      如果

      [F^{prime}(x)=f(x) ]

      [int_{a}^{b} f(x) mathrm{d} x=F(b)-F(a) ]

      这个可以求:(int_a^b(frac 1 x)dx = ln |b|-ln |a|)

      这也是连接定积分和不定积分的桥梁

    对于一些难求的积分,我们可以用数值积分来求,其中常用的是自适应辛普森积分

    辛普森公式

    此公式用二次函数来拟合原函数

    [int_{a}^{b} f(x) mathrm{d} x approx int_{a}^{b}left(A x^{2}+B x+C ight) mathrm{d} x ]

    [=frac{A}{3}left(b^{3}-a^{3} ight)+frac{B}{2}left(b^{2}-a^{2} ight)+C(b-a) ]

    [=frac{2 A(b-a)left(b^{2}+a b+a^{2} ight)+3 B(b+a)(b-a)+6 C(b-a)}{6} ]

    提出(b-a)

    [=frac{(b-a)left(2 A b^{2}+2 A a b+2 A a^{2}+3 B b+3 B a+6 C ight)}{6} ]

    [=frac{(b-a)left(A a^{2}+B a+C+A b^{2}+B b+C+A a^{2}+2 A a b+A b^{2}+2 B b+2 B a+4 C ight)}{6} ]

    [=frac{(b-a)left(f(a)+f(b)+A(a+b)^{2}+2 B(a+b)+4 C ight)}{6} ]

    [=frac{(b-a)left(f(a)+f(b)+4left(Aleft(frac{a+b}{2} ight)^{2}+Bleft(frac{a+b}{2} ight)+C ight) ight)}{6} ]

    [=frac{(b-a)left(f(a)+f(b)+4 fleft(frac{a+b}{2} ight) ight)}{6} ]

    于是可以得到公式:

    [int_{a}^{b} f(x) mathrm{d} x approx frac{(b-a)left(f(a)+f(b)+4 fleft(frac{a+b}{2} ight) ight)}{6} ]

    当然,对于二次函数这是对的

    对于其余情况,(b-a)越小,上面两个式子越接近

    这种情况下我们就要调整精度

    处理精度

    考虑把一段长的区间分成很多段小区间求和

    可是分的太少了不能满足精度要求,太多了会TLE

    那么考虑什么时候停止分下去呢?

    对于当前区间,求出(ans=simpson(l,r),mid=frac{l+r}{2})

    然后求出对于下一层区间的答案:(ls=simpson(l,mid),rs=simpson(mid,r))

    注意此处mid右边不用加一,不是整数域

    如果(|ls+rs-ans|<eps),即满足精度要求,可以停止二分

    考虑到一些小的误差加起来很大,eps要设的比题目要求的小一点

    而且下一层的eps是上一层的二分之一,因为有两个

    代码实现

    double F(...){
    	...
    }
    double simpson(double l,double r){
    	double mid=(l+r)/2.0;
    	return (r-l)/6.0*(F(l)+4.0*F(mid)+F(r));
    } 
    double solve(double l,double r,double ans,double eps){
    	double mid=(l+r)/2.0;
    	double ls=simp(l,mid),rs=simp(mid,r);
    	if(fabs(ls+rs-ans)<eps*15) return ls+rs+(ls+rs-ans)/15;
    	else return solve(l,mid,ls,eps*0.5)+solve(mid,r,rs,eps*0.5);
    }
    

    等一下,好像实现和上面的思路不同?

    if(fabs(ls+rs-ans)<eps*15) return ls+rs+(ls+rs-ans)/15;

    (15)是个啥东西?

    噔 噔 咚

    论证,请(绝望)

    最后移一下项就好了,得到ls+rs+(ls+rs-ans)/15​

    模板

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define db double
    using namespace std;
    db a,b,c,d,l,r;
    db F(db x){
    	return (c*x+d)/(a*x+b);
    }
    db simp(db l,db r){
    	db mid=(l+r)/2.0;
    	return (r-l)/6.0*(F(l)+4.0*F(mid)+F(r));
    }
    db solve(db l,db r,db ans,db eps){
    	db mid=(l+r)/2.0;
    	db ls=simp(l,mid),rs=simp(mid,r);
    	if(fabs(ls+rs-ans)<eps*15) return ls+rs+(ls+rs-ans)/15;
    	else return solve(l,mid,ls,eps*0.5)+solve(mid,r,rs,eps*0.5);
    }
    int main(){
    	scanf("%lf%lf%lf%lf%lf%lf",&a,&b,&c,&d,&l,&r);
    	printf("%.6f",solve(l,r,simp(l,r),1e-8));
    	return 0;
    } 
    

    时间复杂度

    精度不能开太小,开要求精度再多2~3位都很稳

    练习

    找不到题啊。。

    BZOJ2178

    面积并:

    [S=int_l^rf(x)dx ]

    (f(x))为一条垂直于x轴的线的覆盖的长度

    然后就可以用辛普森积分算了

    (f)的话可以求出所有交点,按上点排序,O(n)枚举计算出下一条线是否和当前有交点,并计算长度

    90分代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define db double
    int n;
    const int N = 1001;
    db x[N],y[N],r[N];
    const double eps=1e-3;
    struct node{
    	db u,d;
    }p[N];
    int tp;
    int cmp(const node &aa,const node &bb){
    	return aa.u<bb.u;
    }
    db F(db pos){
    	tp=0;
    	for(int i=1;i<=n;i++){
    		if(pos>=x[i]-r[i]&&pos<=x[i]+r[i]){
    			p[++tp].u=y[i]-sqrt(r[i]*r[i]-(x[i]-pos)*(x[i]-pos));
    			p[tp].d=y[i]+sqrt(r[i]*r[i]-(x[i]-pos)*(x[i]-pos));
    		}
    	}
    	sort(p+1,p+tp+1,cmp);
    	db nu=p[1].u,nd=p[1].d,ans=0;
    	for(int i=2;i<=tp;i++){
    		if(p[i].u<=nd){
    			nd=max(nd,p[i].d);
    		}else{
    			ans+=(nd-nu);
    			nu=p[i].u,nd=p[i].d;
    		}
    	}
    	ans+=(nd-nu);
    	return ans;
    }
    db simp(db l,db r){
    	db mid=(l+r)*0.5;
    	return (r-l)/6.0*(F(l)+4.0*F(mid)+F(r)); 
    }
    db solve(db l,db r,db ans,db eps){
    	db mid=(l+r)*0.5;
    	db ls=simp(l,mid),rs=simp(mid,r);
    	if(fabs(ls+rs-ans)<15.0*eps) return ls+rs+(ls+rs-ans)/15.0;
    	else return solve(l,mid,ls,eps*0.5)+solve(mid,r,rs,eps*0.5);
    }
    int main(){
    	scanf("%d",&n);
    	db ml=1926081700.1,mr=-1926081700.1;
    	for(int i=1;i<=n;i++){   
    		scanf("%lf%lf%lf",&x[i],&y[i],&r[i]);
    		ml=min(x[i]-r[i],ml);
    		mr=max(mr,x[i]+r[i]);
    	}
    	printf("%.3f",solve(ml,mr,simp(ml,mr),eps));
    	return 0;
    }
    

    最后一个点被卡了,认识到此算法只能用来骗分。艹

    闵可夫斯基和

    空间中点集的和

    有一些性质,比如,凸包之间的闵可夫斯基和一定是凸包

    求凸包之间的闵可夫斯基和的方法:把两个凸包的每一条向量都抠出来,按照极角序排序构成新凸包

    实现方法:

        pot P={-inf,-inf},Q={-inf,-inf},R={-inf,-inf};
        n=read(); 
        for(int i=1;i<=n;i++)
        {
            a[i].x=read();a[i].y=read();
            if(dcmp(a[i].y-P.y)==0&&dcmp(a[i].x-P.x)<0)P=a[i];
            if(dcmp(a[i].y-P.y)>0)P=a[i];
            if(i!=1)f[++cnt]=a[i]-a[i-1];if(i==n)f[++cnt]=a[1]-a[i];
        }
        n=read();
        for(int i=1;i<=n;i++)
        {
            b[i].x=read();b[i].y=read();
            if(dcmp(b[i].y-Q.y)==0&&dcmp(b[i].x-Q.x)<0)Q=b[i];
            if(dcmp(b[i].y-Q.y)>0)Q=b[i];
            if(i!=1)f[++cnt]=b[i]-b[i-1];if(i==n)f[++cnt]=b[1]-b[i];
        }
        n=read();
        for(int i=1;i<=n;i++)
        {
            c[i].x=read();c[i].y=read();
            if(dcmp(c[i].y-R.y)==0&&dcmp(c[i].x-R.x)<0)R=c[i];
            if(dcmp(c[i].y-R.y)>0)R=c[i];
            if(i!=1)f[++cnt]=c[i]-c[i-1];if(i==n)f[++cnt]=c[1]-c[i];
        }
        sort(f+1,f+cnt+1,cmp);
        pot k=P+Q+R;p[++tot]=k;
        for(int i=1;i<=cnt;i++)
        {
            k=k+f[i];
            if(i!=cnt&&dcmp(f[i].x*f[i+1].y-f[i].y*f[i+1].x)==0)continue;
            p[++tot]=k;
        }
        tot--;k=p[1];
    

    没有例题,抱歉

    Pick定理

    结论

    在一个平面直角坐标系内,以整点为顶点的简单多边形,设其内部整点数为(a),边上(包括顶点)的整点数为(b),则它的面积为(a+frac b 2 -1)

    证明

    例题

    =模板

    边上的格点数=|dx|和|dy|的最大公约数

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int ol,x1,x2,x3,ya,yb,yc;
    int gcd(int x,int y) {
    	return y==0?x:gcd(y,x%y);
    }
    int area() {
    	return abs((x2-x1)*(yc-ya)-(x3-x1)*(yb-ya))/2;
    }
    int cal(int x1,int ya,int x2,int yb) {
    	int dx,dy;
    	if(x1<x2)dx=x2-x1;
    	else dx=x1-x2;
    	if(ya<yb)dy=yb-ya;
    	else dy=ya-yb;
    	return gcd(dx,dy);
    }
    int main() {
    	while(scanf("%d%d%d%d%d%d",&x1,&ya,&x2,&yb,&x3,&yc)) {
    		if(!x1&&!x2&&!x3&&!ya&&!yb&&!yc)break;
    		ol=cal(x1,ya,x2,yb)+cal(x2,yb,x3,yc)+cal(x3,yc,x1,ya);
    		printf("%d
    ",area()-ol/2+1);
    	}
    	return 0;
    }
    

    后记

    其实 val.2 比 val.3 难且重要

    但是不重要不代表不学呀

    辛普森积分还是挺实用的,我觉得

    没有val.4了,最多写写做题记录

  • 相关阅读:
    autocomplete自动完成搜索提示仿google提示效果
    实现子元素相对于父元素左右居中
    javascript 事件知识集锦
    让 IE9 以下的浏览器支持 Media Queries
    「2013124」Cadence ic5141 installation on CentOS 5.5 x86_64 (limited to personal use)
    「2013420」SciPy, Numerical Python, matplotlib, Enthought Canopy Express
    「2013324」ClipSync, Youdao Note, GNote
    「2013124」XDMCP Configuration for Remote Access to Linux Desktop
    「2013115」Pomodoro, Convert Multiple CD ISO to One DVD ISO HowTo.
    「2013123」CentOS 5.5 x86_64 Installation and Configuration (for Univ. Labs)
  • 原文地址:https://www.cnblogs.com/lcyfrog/p/11712272.html
Copyright © 2011-2022 走看看