zoukankan      html  css  js  c++  java
  • P2742 [USACO5.1]圈奶牛Fencing the Cows /【模板】二维凸包

    gate

    二维凸包是指覆盖平面上(n)个点的最小的凸多边形。
    (Andrew)算法是一种求凸包的常用算法,它的时间复杂度是(O(nlogn))

    算法流程

    1. 以x为第一关键字,y为第二关键字排序。
    2. 从1号点(最左下的一点)开始遍历,
    • 若当前点在栈顶两个元素在直线的左边则入栈,
    • 否则若在右边,说明有更优方案,栈顶的点出栈,直到在左边为止。
      可以得到下凸包。
    1. 按相反方向重复第二步,得到上凸包。

    二维向量的叉乘

    想要判断两条直线的位置关系,需要用到向量的叉乘这一前置知识。
    定义:设两个向量分别为(vec{a}=(x_1,y_1),vec{b}=(x_2,y_2))
    那么它们的叉乘即为(vec{a} imesvec{b}=x_1y_2-x_2y_1),它也是一个向量。
    性质:(vec{a} imesvec{b}=-vec{b} imesvec{a})
    几何意义:以两向量为邻边的平行四边形的有向面积;
    定义向量(vec{a})(vec{b})

    • (vec{a} imesvec{b}<0)时,(vec{b})(vec{a})的顺时针方向;
    • (vec{a} imesvec{b}=0)时,(vec{a})(vec{b})共线(可以反向);
    • (vec{a} imesvec{b}>0)时,(vec{b})(vec{a})的逆时针方向。

    因此,要判断点(z)是否在(x,y)所连直线的左边,可以判断是否有(vec{xy} imesvec{yz}>0)

    代码如下

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define MogeKo qwq
    using namespace std;
    
    const int maxn = 1e5+10;
    int n,cnt;
    double ans;
    
    struct node {
    	double x,y;
    	bool operator < (const node & N) const {
    		if (x == N.x) return y < N.y;
    		return x < N.x;
    	}
    } a[maxn],b[maxn];
    
    double mul(node v1,node v2,node v3) {
    	double x_1,x_2,y_1,y_2;
    	x_1 = v2.x-v1.x, x_2 = v3.x-v2.x;
    	y_1 = v2.y-v1.y, y_2 = v3.y-v2.y;
    	return (x_1*y_2 - x_2*y_1);
    }
    
    double cal(node v1,node v2) {
    	double xx,yy;
    	xx = v1.x - v2.x;
    	yy = v1.y - v2.y;
    	return sqrt(xx*xx + yy*yy);
    }
    
    void solve(int op) {
    	cnt = 1;
    	b[1] = a[1];
    	for(int i = 2; i <= n; i++) {
    		if(op == 1) while(cnt > 1 && mul(b[cnt-1],b[cnt],a[i]) <= 0) cnt--;
    		if(op == 2) while(cnt > 1 && mul(b[cnt-1],b[cnt],a[i]) >= 0) cnt--;
    		b[++cnt] = a[i];
    	}
    	for(int i = 1; i < cnt; i++)
    		ans += cal(b[i],b[i+1]);
    }
    
    int main() {
    	scanf("%d",&n);
    	for(int i = 1; i <= n; i++)
    		scanf("%lf%lf",&a[i].x,&a[i].y);
    	sort(a+1,a+n+1);
    	solve(1);
    	solve(2);
    	printf("%.2lf
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    linux uniq 命令实用手册
    linux sort 命令实用手册
    linux awk 命令实用手册
    如何高效使用vim
    15个有趣好玩的linux shell 命令
    一篇文章带你编写10种语言HelloWorld
    如何用hugo 搭建博客
    c++中的exit()
    枚举数据类型C++
    常见的字符测试函数
  • 原文地址:https://www.cnblogs.com/mogeko/p/12564556.html
Copyright © 2011-2022 走看看