计算几何 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. 中标麒麟neokylin信息查看

    中标麒麟Neokylin系统版本信息: # nkvers ############## NeoKylin Linux Version################# Release: NeoKyli ...

  2. shell脚本简单例子

    eg: Expect: 1.用环境变量RANDOM随机生成一个100以内的随机数 2.read读取当前输入 3.当前输入对比随机生成的数 4.当两个数相等时跳出苏循环,并计数(比较n次结果才相等) # ...

  3. Python列表中的字典按照该字典下的键值进行排序

    列表中的字典按照该字典下的键值进行排序 这算是排序中比较复杂的一种情况吧,多重嵌套,按照某种规则进行排序.如下面这个json(注:这里这是该列表中的一个项): [ { "stat" ...

  4. cocoapods 安装使用详解

    http://blog.csdn.net/showhilllee/article/details/38398119 http://www.jianshu.com/p/1222dd6c4271  删除 ...

  5. pandas学习(四)--数据的归一化

    欢迎加入python学习交流群 667279387 Pandas学习(一)–数据的导入 pandas学习(二)–双色球数据分析 pandas学习(三)–NAB球员薪资分析 pandas学习(四)–数据 ...

  6. flink基本原理

    一.简介 开源流式处理系统在不断地发展,从一开始只关注低延迟指标到现在兼顾延迟.吞吐与结果准确性,在发展过程中解决了很多问题,编程API的易用性也在不断地提高.本文介绍一下 Flink 中的核心概念, ...

  7. R语言for循环

    基本语法:for (name in expr_1) expr_2 实例操作: 1.构造矩阵 x=array(,dim=c(,)) # 构造四阶矩阵 数值全为0 :){ :){ x[i,j]=/(i+j ...

  8. Dijkstra(迪杰斯特拉求最短路径)-02-网络延迟时间

    有 N 个网络节点,标记为 1 到 N. 给定一个列表 times,表示信号经过有向边的传递时间. times[i] = (u, v, w),其中 u 是源节点,v 是目标节点, w 是一个信号从源节 ...

  9. Jenkins编译过程中出现ERROR_ Failed to parse POMs错误

    一.在使用jenkins编写过程中突然出现以下问题 Parsing POMs Established TCP socket on 59407 [java] $ java -cp /var/lib/je ...

  10. CCF-CSP题解 201403-4 无线网络

    新建不超过\(k\)个无线路由器,求使路由器1.2连通最少的中间路由器. 首先常规建图,将相距不超过\(r\)的路由器(包括新建的)相连. 想到了分层\(dijkstra\).类似的,作\(bfs\) ...