[BZOJ1007][HNOI2008]水平可見直線
阿新 • • 發佈:2018-07-29
put n+1 ons std con 凸包 clas ret 細節題
這個題我一開始看的時候有凸包的感覺,無奈對算法掌握不是很熟悉,沒有成功的解決,看了題解才知道這個題竟然如此的水,就是一個凸包的模板。
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; }
這個題前後也是折騰了很久,一開始cross
那裏寫反了,gg*1;後來發現沒有用double
,gg*2;再後來沒有寫實數比較,gg*3;最後才發現自己沒有處理好斜率相同的情況,gg*4,前前後後交了5次,這才改好了這個題,仔細回想一下,如果是考試的話,我大概就已經gg*inf了,以後對於這種細節題還是要仔細。
以及這個凸包的寫法簡直太好了,無需提前入棧前兩個元素,優美。
[BZOJ1007][HNOI2008]水平可見直線