美文网首页
寄蒜几盒极速入门

寄蒜几盒极速入门

作者: Hiyoiria | 来源:发表于2018-01-20 23:03 被阅读0次

这可能是我电脑上唯一一个可以记中文还可以打代码还可以保存的地方了 so sad

决定跟着cls的课件过一遍
要把几个板子囤好 (据说PKU爱考寄蒜几盒板子)
不过我发现一到markdown下我就喜欢折腾
感觉排版突然就重要了起来

  1. 向量结构体与基本运算
typedef double db;
struct po{
    db x,y;
    po (db x=0,y=0):x(x),y(y) {}
};
const db eps=1e-9;
po operator + (po a,po b) { return po(a.x+b.x,a.y+b.y); }
po operator - (po a,po b) { return po(a.x-b.x,a.y-b.y); }
po operator * (po a,db b) { return po(a.x*b,a.y*b); }
po operator / (po a,db b) { return po(a.x/b,a.y/b); }
db sqr(db x) { return x*x; }
db dis(po a,po b) { return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)); }
int cmp(db x) { return fabs(x)<eps?0:(x<0?-1:1); }
bool operator == (po a,po b) { return (!cmp(a.x-b.x))&&(!cmp(a.y-b.y));  }
  1. 点积与叉积
    点积是个值 而叉积是个向量
    用的更多的大概是叉积?
    点积 -> x1x2+y1y2 叉积 ->x1y2-x2y1
    点积是一个向量到另一个向量的投影 乘cos 可以用于求cos
    叉积是垂直与ab向量所成平面的向量 是两向量间所成平行四边形的面积 可以用于求sin
    叉积正负可以用于判相对位置
    a×b >0 a在b的顺时针方向 a×b==0共线但不一定同方向
    理解为a×b就是从a往b扫过去 而从左往右扫为正
db operator ^ (po a,po b) { return a.x*b.x+a.y*b.y; }
db operator * (po a,po b) { return a.x*b.y-a.y*b.x; }

点/叉积的一些应用

  1. 折线拐向
    首先把两点转为一个向量 判断向量之间的相对位置
    v1=p2-p0 v2=p1-p0
    讨论v1×v2 <0向右拐 >0向左拐 ==0共线 请用移动的视角来判断左右!!!

  2. 点在线段上
    如果是直线很好办 叉积一下判0即可
    如果是线段就要避免在延长/反向延长线上 那么判断一下min/max就好

  3. 判线段p0p1与直线q0q1是否相交
    由于快要没时间了就不看两线段的问题了
    令v1=p0-q0,v2=p1-q0,v2=q1-q0 使v1v2与v2v3同号即可使p0 p1分居直线两侧

  4. 点到线段距离
    记住叉积是平行四边形面积 那么就出然后除底边就好
    首先要判垂足是否在线段上 不在则表现为cos为负
    而且cos可以反映出离哪边比较近

  5. 求交点
    可以暴力表达式或者用点和方向表示向量

  6. 极角排序
    一判象限 二判叉积(根据顺逆定正负) 三判x轴距离

int xx(po a){
    if (a.x>0&&a.y>=0) return 1;
    if (a.x<=0&&a.y>0) return 2;
    if (a.x<0&&a.y<=0) return 3;
    return 4;
}
bool jcmp(po a,po b){
    if (a==b) return 1;
    po x=a-o,y=b-o; int l=xx(x),r=xx(y);
    if (l==r) return (x*y<0)||(x*y==0&&x.x<y.x);
    return l<r;
}
  1. 多边形面积
    化成三角形来搞 排个序然后每次叉积最后/2
db polys(po *p,int n){
    db res=0;
    for (int i=1;i<n-1;++i) res+=(p[i]-p[0])*(p[i+1]-p[0]);
    return res/2;
}
  1. 凸包
    先排序 直接按x,y分别为关键字
    先丢两个点进去 然后从第三个点开始
    while不是在之前方向的左边就弹 符合就加进去
    做两遍 分别求出下/上凸包
bool tbcmp (po a,po b) { return a.x==b.x?a.y<b.y:a.x<b.x; }
int tb(po *p,int n){
    sort(p+1,p+n+1,chcmp);
    int m=0;
    for (int i=1;i<=n;++i){
        while (m>1&&(st[m]-st[m-1])*(a[i]-st[m-1])<0) m--;
        st[++m]=a[i];
    }
    int k=m;
    for (int i=n-1;i;--i){
        while (m>k&&(st[m]-st[m-1])*(a[i]-st[m-1])<=0) m--;
        st[++m]=a[i];
    }
    return m;
}

注意几点细节 第一次弹栈要保证至少有两个元素 第二次要保证大于下凸包元素
然后两次都是<0 第二次还要把等于也弹掉
第二次求上凸包从n-1开始 最开始可能要去重

6.旋转卡壳 4 3 ka qiao gif此生难忘系列
求平面最远点对
每个点只可能和对踵点有贡献 然后这东西是O(n)的
我们考虑枚举一条边 然后找到其距离最远的点
会形成三角形 然后面积是单峰的
由于是在凸包上做 所以后面的边的对点一定也是单调在前面的边的后面的
然后由于是判面积 那么丢给叉积搞搞就好 不过这里有一些技巧(觉得自己背不下来 还是手推吧)
把面积比较写成叉积与0比较然后根据叉积是面积有
Cross(A,B) - Cross(A,C) = Cross(A,B-C)
那么就搞一搞就好了

db rc(po *p,int n){
    n=tb(p,n),p[0]=p[n];
    db ans=0;
    for (int i=0,j=1;i<n;++i){
        while ((p[i+1]-p[i])*(p[j+1]-p[j])>0) j=(j+1)%n;
        ans=max(ans,max(dis(p[j],p[i]),dis(p[j+1],p[i+1])));
    }
    return ans;
}

这里注意我们从0开始然后使其<n的话就可以用取模的方式循环
以及while那里是没有等于的
然后这东西貌似还可以拿来求两个凸多边形之间的最小距离
枚举其中一个的边 然后另一个就搞点就好 这个也是单调的

  1. 半平面交 又名半个飞机
    先把向量们极角排序 然后写个斜率优化??
struct ln{
    po p,v;
}l[N];
bool comp(ln x,ln y){
    db t=x.v*y.v;
    return (t>0)||((t==0)&&x.v*(y.p-x.p)>0);
}//先右后左 如果平行则返通过起点连线与向量方向判定
bool lcmp(ln x,ln y){
    if (x.v.y==0&&y.v.y==0) return x.v.x<y.v.x;
    if (x.v.y<=0&&y.v.y<=0) return comp(x,y);
    if (x.v.y>0&&y.v.y>0) return comp(x,y);
    return x.v.y<y.v.y;//逆时针
}
bool left(ln x,po p) { return x.v*(p-x.p)>0; }//点在线左边则点与起点向量在原向量左
po jd(ln x,ln y){
    po t=x.p-y.p;
    db u=(y.v*t)/(y.v,x.v);
    return x.p+u*x.v;
}//利用面积之比 同底高之比
void hpi(){
    sort(l+1,l+n+1,lcmp);
    int m=0;
    for (int i=1;i<=n;++i){
        if (l[i].v*l[i-1].v||i==1) m++;//平行特判
        l[m]=l[i];
    }
    int h=1,t=2; s[1]=l[1],s[2]=l[2];
    for (int i=3;i<=m;++i){
        while (h<t&&left(l[i],jd(s[t],s[t-1]))) t--;
        while (h<t&&left(l[i],jd(s[h],s[h+1]))) h++;
        s[++t]=l[i];
    }
    while (h<t&&left(s[h],jd(s[t],s[t-1]))) t--;
    while (h<t&&left(s[t],jd(s[h],s[h+1]))) h++;//消除无用
    s[++t]=s[h];//形成环
    for (int i=h;i<t;++i) p[++cnt]=jd(s[i],s[i+1]);
}
  1. 动态凸包 大致就用平衡树/cdq来维护凸包 每次加入一个点就找前驱后继来判断这个点是属于在凸包内/直接加入/要删掉其他点的哪种情况就好
    不会去学了

大概就是以上

一些套路
枚举特殊点/边 极角排序后利用单调性 还经常可以旋转卡壳
展开叉积 x/y分开处理 二分
另外
上面的板子正确性有待确认

相关文章

  • 寄蒜几盒极速入门

    这可能是我电脑上唯一一个可以记中文还可以打代码还可以保存的地方了 so sad 决定跟着cls的课件过一遍要把几个...

  • PHP极速入门

    PHP视频教程全集下载-PHP视频教程排行以及深度解析: 带领我们一起走进PHP的世界。 PHP是世界上最好的编程...

  • 极速入门webpack

    纯新手向在学习webpack之前,我们必须已经了解了,什么是前端模块化开发。 每一个新手开发者去学习一项新的技术时...

  • TensorFlow极速入门

    雷锋网(公众号:雷锋网)按:本文原载于Qunar技术沙龙,原作者已授权雷锋网发布。作者孟晓龙,2016年加入Qun...

  • Ruby极速入门

    因为工作关系需要用到Ruby和Rails,于是在端午假期里花了点时间快速的学习了下。这里做一个简单的记录。 基础数...

  • RabbitMQ 极速入门

    角色: ConnectionFactory 连接工厂 Connection 一个连接 Channel 数据通信通道...

  • redux 极速入门

    创建一个管理者, 导出state, 放在store里面 创建一个store window.... 的作用是能使用r...

  • GitHub使用总结

    前言 下面是我对GitHub使用总结的文章 GitHub快速入门: GitHub极速入门-程序员必备技能 GitH...

  • Spring Security系列之极速入门与实践教程

    @[TOC](Spring Security系列之极速入门与实践教程) 1. Spring Security Sp...

  • Go 语言极速入门

    本系列文章主要是记录《Go 语言实战》和《Google 资深工程师深度讲解 Go 语言》的学习笔记。 Go 语言极...

网友评论

      本文标题:寄蒜几盒极速入门

      本文链接:https://www.haomeiwen.com/subject/orqxaxtx.html