计算几何 val.3

自适应辛普森法

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

定积分

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

表示法为

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

引入

计算方法:

  1. 分成一堆小区间

    \[\int_{a}^{b} f(x) \mathrm{d} x=\lim _{n \rightarrow \infty} \sum_{i=1}^{n} \frac{b-a}{n} f\left(a+\frac{b-a}{n} i\right)
    \]

  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\right) \mathrm{d} x
\]

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

\[=\frac{2 A(b-a)\left(b^{2}+a b+a^{2}\right)+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\right)}{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\right)}{6}
\]

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

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

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

于是可以得到公式:

\[\int_{a}^{b} f(x) \mathrm{d} x \approx \frac{(b-a)\left(f(a)+f(b)+4 f\left(\frac{a+b}{2}\right)\right)}{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\n",area()-ol/2+1);
}
return 0;
}

后记

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

但是不重要不代表不学呀

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

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

计算几何 val.3的更多相关文章

  1. 计算几何 val.2

    目录 计算几何 val.2 几何单位结构体板子 旋转卡壳 基础概念 求法 模板 半平面交 前置芝士:线段交 S&I算法 模板 最小圆覆盖 随机增量法 时间复杂度 模板 后记 计算几何 val. ...

  2. 计算几何 val.1

    目录 计算几何 val.1 向量的点积 向量的叉积 一种奇怪的三角剖分求面积 凸包 点绕点旋转 后记 计算几何 val.1 本文并不是入门文章,供有高中数学基础的阅读 主要写一些重要的点和注意事项吧 ...

  3. ACM 计算几何中的精度问题(转)

    http://www.cnblogs.com/acsmile/archive/2011/05/09/2040918.html 计算几何头疼的地方一般在于代码量大和精度问题,代码量问题只要平时注意积累模 ...

  4. POJ 1066 Treasure Hunt(计算几何)

    题意:给出一个100*100的正方形区域,通过若干连接区域边界的线段将正方形区域分割为多个不规则多边形小区域,然后给出宝藏位置,要求从区域外部开辟到宝藏所在位置的一条路径,使得开辟路径所需要打通的墙壁 ...

  5. POJ 2318 TOYS(计算几何)

    题目大意:有一个矩形盒子,盒子里会有一些木块线段,并且这些线段是按照顺序给出的,有n条线段,把盒子分层了n+1个区域,然后有m个玩具,这m个玩具的坐标是已知的,问最后每个区域有多少个玩具 解题思路:因 ...

  6. TOYS - POJ 2318(计算几何,叉积判断)

    题目大意:给你一个矩形的左上角和右下角的坐标,然后这个矩形有 N 个隔板分割成 N+1 个区域,下面有 M 组坐标,求出来每个区域包含的坐标数.   分析:做的第一道计算几何题目....使用叉积判断方 ...

  7. POJ 1556 计算几何+最短路

    代码1: #include<iostream> #include<stdio.h> #include<string> #include<string.h> ...

  8. 【BZOJ5316】[JSOI2018]绝地反击(网络流,计算几何,二分)

    [BZOJ5316][JSOI2018]绝地反击(网络流,计算几何,二分) 题面 BZOJ 洛谷 题解 很明显需要二分一个答案. 那么每个点可以确定的范围就是以当前点为圆心,二分出来的答案为半径画一个 ...

  9. POJ - 2031 Building a Space Station(计算几何+最小生成树)

    http://poj.org/problem?id=2031 题意 给出三维坐标系下的n个球体,求把它们联通的最小代价. 分析 最小生成树加上一点计算几何.建图,若两球体原本有接触,则边权为0:否则边 ...

随机推荐

  1. JVM虚拟机详解+Tomcat性能优化

    1.JVM(java virtual mechinal) ()JVM有完善的硬件架构,如处理器.堆栈.寄存器当,还具有相应的指令系统. ()JVM的主要工作时解释自己的指令集(即字节码),并映射到本地 ...

  2. jsp实现增加数据功能

    1. 环境的搭建 软件 数据库  sql myeclipse 8.0  tomcat 6.0 2. 安装完 myeclipse 配置下  部署tomcat 6.0 =1=> =2=>  新 ...

  3. 解惑Python模块学习,该如何着手操作...

    Python模块 晚上和朋友聊天,说到公司要求精兵计划,全员都要有编程能力.然后C.Java.Python-对于零基础入门的,当然是选择Python的人较多了.可朋友说他只是看了简单的语法,可pyth ...

  4. cluster模块设置子进程的stdio

    原因 子进程的stdout及stderr需要被设置为某个文件,根据文档 setupMaster 说明,需要设置stdio数组: c.setupMaster({ exec: `${cwd}/c.js`, ...

  5. luogu P1509 找啊找啊找GF

    题目背景 sqybi现在看中了n个MM,我们不妨把她们编号1到n.请MM吃饭是要花钱的,我们假设请i号MM吃饭要花rmb[i]块大洋.而希望骗MM当自己GF是要费人品的,我们假设请第i号MM吃饭试图让 ...

  6. HDU4117 GRE WORDS(AC自动机+线段树维护fail树的dfs序)

    Recently George is preparing for the Graduate Record Examinations (GRE for short). Obviously the mos ...

  7. HDU1848 Fibonacci again and again(SG 函数)

    任何一个大学生对菲波那契数列(Fibonacci numbers)应该都不会陌生,它是这样定义的: F(1)=1; F(2)=2; F(n)=F(n-1)+F(n-2)(n>=3); 所以,1, ...

  8. CoderForces999B- Reversing Encryption

    time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...

  9. JS-引用类型的参数传递

  10. django----cookie与session 和 中间件

    目录 cookie与session简介及操作 cookie django中操作cookie cookie超时时间 删除cookie session session操作 设置 key value发生了什 ...