zoukankan      html  css  js  c++  java
  • [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了,所以以后对于这种细节题还是要仔细。

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

  • 相关阅读:
    复习一些奇怪的题目
    NOIP 考前 KMP练习
    NOIP 考前 并查集复习
    NOIP 考前 Tarjan复习
    NOIP 考前 图论练习
    BZOJ 1468 树分治
    Codeforces Round #376 (Div. 2)
    CodeVS 线段覆盖1~5
    Luogu 3396 权值分块
    BZOJ 2743 树状数组
  • 原文地址:https://www.cnblogs.com/wyxwyx/p/bzoj1007.html
Copyright © 2011-2022 走看看