• Graham 求静态凸包


    首先确定一个一定在凸包里的点 base, 比如 y 坐标最小的点。
    然后用一个射线按照某种方式转一圈, 每一时刻只保留最外的点 x, 上一个加入凸包的点 y, 上上个 z, 显然 (z,y) 转到 (y,x) 需要 δ 的方向必须与原来射线转的方向一致。

    在 base 为原点的意义下共线的两个向量, 比较长度只需比较 x 坐标的大小, 或是比较 y 坐标的大小。

    下面是两份有细微区别的代码。
    1

    #include <bits/stdc++.h>
    typedef double db;
    using namespace std;
    
    const int N = 1e5 + 23;
    const db EPS = 1e-15;
    
    struct po {
    	db x , y;
    	po() {
    	}
    	po(db x_, db y_) : x(x_), y(y_) {
    	}
    	inline po operator + (po b) {return po(x+b.x, y+b.y);}
    	inline po operator - (po b) {return po(x-b.x, y-b.y);}
    	inline db operator % (po b) {return x*b.y - y*b.x;}
    	inline db len() {return sqrt(x*x+y*y);}
    } p[N], s[N];
    
    bool cmp(po s1, po s2) {
    	db tmp = ((s1-p[1]) % (s2-p[1]));
    	return (tmp < 0) || (tmp == 0 && s1.x < s2.x);
    }
    
    int n;
    
    int main() {
    	scanf("%d", &n);
    	for(int i = 1; i <= n; ++i) {
    		scanf("%lf%lf", &p[i].x, &p[i].y);
    		if(p[i].y < p[1].y) swap(p[1], p[i]);
    	}
    	sort(p+2, p+1+n, cmp);
    	int cnt = 1;
    	s[1] = p[1];
    	for(int i = 2; i <= n; ++i) {
    		while(cnt > 1 && (s[cnt]-s[cnt-1])%(p[i]-s[cnt]) >= 0) --cnt;
    		s[++cnt] = p[i];
    	}
    	double ans = (s[cnt] - s[1]).len();
    	for(int i = 1; i < cnt; ++i) ans += (s[i+1] - s[i]).len();
    	printf("%.2lf", ans);
    	return 0;
    }
    

    2

    #include <bits/stdc++.h>
    typedef double db;
    using namespace std;
    
    const int N = 1e5 + 23;
    const db EPS = 1e-15;
    
    struct po {
    	db x , y;
    	po() {
    	}
    	po(db x_, db y_) : x(x_), y(y_) {
    	}
    	inline po operator + (po b) {return po(x+b.x, y+b.y);}
    	inline po operator - (po b) {return po(x-b.x, y-b.y);}
    	inline db operator % (po b) {return x*b.y - y*b.x;}
    	inline db len() {return sqrt(x*x+y*y);}
    } p[N], s[N];
    
    bool cmp(po s1, po s2) {
    	db tmp = ((s1-p[1]) % (s2-p[1]));
    	return (tmp > 0) || (tmp == 0 && s1.x < s2.x);
    }
    
    int n;
    
    int main() {
    	scanf("%d", &n);
    	for(int i = 1; i <= n; ++i) {
    		scanf("%lf%lf", &p[i].x, &p[i].y);
    		if(p[i].y < p[1].y) swap(p[1], p[i]);
    	}
    	sort(p+2, p+1+n, cmp);
    	int cnt = 1;
    	s[1] = p[1];
    	for(int i = 2; i <= n; ++i) {
    		while(cnt > 1 && (s[cnt]-s[cnt-1])%(p[i]-s[cnt]) <= 0) --cnt;
    		s[++cnt] = p[i];
    	}
    	double ans = (s[cnt] - s[1]).len();
    	for(int i = 1; i < cnt; ++i) ans += (s[i+1] - s[i]).len();
    	printf("%.2lf", ans);
    	return 0;
    }
    
  • 相关阅读:
    数据绑定控件的上下文Container dodo
    jquery的调试利器:Firebug使用详解 dodo
    Scrum中的角色 dodo
    jquery easyui datagrid的增加,修改,删除 dodo
    计划扑克(Planning Poker) dodo
    windows2003 IIS 服务启动失败,提示‘另一个程序正在使用此文件,进程无法访问',解决方法 dodo
    控件包含代码块(即 <% ... %>),因此无法修改控件集合 dodo
    AppendFormat System.FormatException: 输入字符串的格式不正确 dodo
    Scrum中的燃烧曲线(Burndown Chart) dodo
    在类中获取、使用当前页面 Page 对象的引用 dodo
  • 原文地址:https://www.cnblogs.com/tztqwq/p/14333813.html
Copyright © 2020-2023  润新知