• [HNOI2008]水平可见直线


    Description

    BZOJ1007

    Solution

    这个题我一开始看的时候有凸包的感觉,无奈对算法应用掌握的不是很好,没有成功的解决。看了题解才知道这个题竟然如此的水,就是一个凸包的模板。

    Code

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    
    typedef double LL; // mark
    const int N = 50000 + 10;
    const double eps = 1e-10;
    
    struct line {
    	LL k, b;
    	line (LL x = 0, LL y = 0) : k(x), b(y) {}
    } l[N];
    int stl, s[N], p[N];
    int n;
    
    LL cross(line a, line b, line c) { // 判断a与b的交点是否在b与c的交点的左侧 
    	return (b.b - a.b) * (b.k - c.k) - (a.k - b.k) * (c.b - b.b); // mark
    }
    
    bool cmp(int a, int b) {
    	if (fabs(l[a].k - l[b].k) < eps) return l[a].b < l[b].b ;
    	else return l[a].k < l[b].k;
    }
    
    bool check(int a, int b, int c) {
    	double res = cross(l[a], l[b], l[c]);
    	return fabs(res) <= eps || res <= 0;
    }
    
    inline void cvx() { // mark
    	std::sort(p+1, p+n+1, cmp);
    	for (int i = 1; i <= n; ++i) {
    		while (stl) {
    			if (fabs(l[p[i]].k - l[s[stl]].k) < eps) stl--;
    			else if (stl>1 && check(p[i], s[stl], s[stl-1])) stl--;
    			else break;
    		}
    		s[++stl] = p[i];
    	}
    	
    }
    
    int main() {
    	scanf("%d", &n);
    	if (n == 1) { puts("1 "); return 0; }
    	for (int i = 1; i <= n; ++i) {
    		scanf("%lf%lf", &l[i].k, &l[i].b);
    		p[i] = i;
    	}
    	
    	cvx();
    	std::sort(s+1, s+1+stl);
    	for (int i = 1; i <= stl; ++i) printf("%d ", s[i]);
    	return 0;
    }
    
    

    Note

    这个题前后也是折腾了很久,一开始cross那里写反了,gg*1;后来发现没有用double,gg*2;再后来没有写实数比较,gg*3;最后才发现自己没有处理好斜率相同的情况,gg*4,前前后后交了5次,这才改好了这个题,仔细回想一下,如果是考试的话,我大概就已经gg*inf了,所以以后对于这种细节题还是要仔细。

    以及这个凸包的写法简直太好了,无需提前入栈前两个元素,优美。

  • 相关阅读:
    作业7-英文词频统计预备,组合数据类型练习
    作业6-凯撒编码、GDP格式化输出、九九乘法表
    作业5-字符串操作
    作业3-turtle库基础练习
    作业2-Python基础练习
    理解管理信息系统
    Git-git rebase详解
    C语言中基本的数据类型
    读取配置文件的C语言接口实现
    Linux之异步IO机制分析
  • 原文地址:https://www.cnblogs.com/wyxwyx/p/bzoj1007.html
Copyright © 2020-2023  润新知