HDU 4946 凸包
给你n个点,具有速度,一个位置如果有其他点能够先到,则不能继续访问,求出里面这些点哪些点是能够无限移动的。
首先我们考虑到,一个速度小的和一个速度大的,速度小的必定只有固定他周围的一定区域是它先到的,而其他地方都是速度大的先到。
再来如果有相同速度的两点,前连线的中垂线则是它们先到的界限,如果一个点在多边形的内部,那么它必定会被与其他点连线的中垂线所包围。
因此,只要选出最大速度的点,在里面找凸包即可。但是还有很多细节,比如点重合的情况...如果速度一样的点重合,该点也不能无限移动,但是求凸包时不能把这个点直接去掉,不然会有问题。
/** @Date : 2017-09-24 16:52:10 * @FileName: HDU 4946 凸包.cpp * @Platform: Windows * @Author : Lweleth (SoungEarlf@gmail.com) * @Link : https://github.com/ * @Version : $Id$ */ #include <bits/stdc++.h> #define LL long long #define PII pair<int ,int> #define MP(x, y) make_pair((x),(y)) #define fi first #define se second #define PB(x) push_back((x)) #define MMG(x) memset((x), -1,sizeof(x)) #define MMF(x) memset((x),0,sizeof(x)) #define MMI(x) memset((x), INF, sizeof(x)) using namespace std; const int INF = 0x3f3f3f3f; const int N = 1010; const double eps = 1e-8; struct point { double x, y; double v; int idx; point() {} point(double _x, double _y) { x = _x, y = _y; } point operator -(const point &b) const { return point(x - b.x, y - b.y); } double operator *(const point &b) const { return x * b.x + y * b.y; } double operator ^(const point &b) const { return x * b.y - y * b.x; } }; double xmult(point p1, point p2, point p0) { return (p1 - p0) ^ (p2 - p0); } double distc(point a, point b) { return sqrt((double)((b - a) * (b - a))); } int sign(double x) { if(fabs(x) < eps) return 0; if(x < 0) return -1; else return 1; } //////// point stk[N]; point p[N]; int cmp(point a, point b)//以p[0]基准 极角序排序 { int t = xmult(a, b, p[0]); if(t > 0) return 1; if(t == 0) return distc(a, p[0]) < distc(b, p[0]); if(t < 0) return 0; } int cmpC(point a, point b)//水平序排序 { if(sign(a.x - b.x) == 0 && sign(a.y - b.y) == 0) return a.v > b.v; return sign(a.x - b.x) < 0 || (sign(a.x - b.x) == 0 && sign(a.y - b.y) < 0); } int cmpV(point a, point b) { return a.v > b.v; } /* int GrahamA() { double mix, miy; mix = miy = 1e10; int pos = 0; for(int i = 0; i < n; i++) { if(p[i].y < miy || (p[i].y == miy && p[i].x < mix)) { mix = p[i].x, miy = p[i].y; pos = i; } } swap(p[0], p[pos]); sort(p + 1, p + n, cmp); int top = 0; stk[0] = p[0]; stk[1] = p[1]; for(int i = 0; i < n; i++) { while(top >= 2 && sign(xmult(stk[top - 2], stk[top - 1], p[i])) < 0) top--; stk[top++] = p[i]; } //stk[++top] = p[0]; return top; }*/ int ans[550]; int Graham(point p[], int n)//水平序 { sort(p, p + n, cmpC); int top = 0; /// for(int i = 0; i < n; i++) if(p[i].x == p[i + 1].x && p[i].y == p[i + 1].y && p[i].v == p[i + 1].v)//细节:注意比较速度,或者是特判下最后一个... ans[p[i].idx] = -1; /// for(int i = 0; i < n; i++) { if(ans[p[i].idx] == -1)//// continue; while(top >= 2 && sign(xmult(stk[top - 2], stk[top - 1], p[i])) < 0) top--; stk[top++] = p[i]; } //cout << top << endl; int tmp = top; for(int i = n - 2; i >= 0; i--) { if(ans[p[i].idx] == -1)//// continue; while(top > tmp && sign(xmult(stk[top - 2], stk[top - 1], p[i])) < 0) top--; stk[top++] = p[i]; } if(n > 1) top--; ///// for(int i = 0; i < top; i++) ans[stk[i].idx] = 1; //sort(p, p + n, cmpC); for(int i = 0; i < n; i++) if(p[i].x == p[i + 1].x && p[i].y == p[i + 1].y && p[i].v == p[i + 1].v) ans[p[i].idx] = ans[p[i + 1].idx] = 0; ///// return top; } int main() { int icase = 0; int n; while(~scanf("%d", &n) && n) { MMF(ans); MMF(stk); for(int i = 0; i < n; i++) { double x, y, v; scanf("%lf%lf%lf", &x, &y, &v); p[i] = point(x, y); p[i].v = v; p[i].idx = i; } sort(p, p + n, cmpV); printf("Case #%d: ", ++icase); if(p[0].v == 0) { for(int i = 0; i < n; i ++) printf("0"); printf("\n"); continue; } int pos = 0; for(int i = 0; i < n; i++) { pos = i; if(p[i].v != p[i + 1].v) break; } int tot = Graham(p, pos + 1); for(int i = 0; i < n; i++) printf("%d", ans[i]); printf("\n"); } return 0; } /* 5 0 0 6 3 3 6 1 1 6 0 3 6 3 0 6 9 0 0 3 0 1 3 0 2 3 1 0 3 1 1 3 1 2 3 2 0 3 2 1 3 2 2 3 3 0 0 3 1 1 2 2 2 1 3 0 0 3 0 0 3 0 0 3 8 1 1 3 2 1 3 3 1 3 3 2 3 2 2 3 1 2 3 1 3 3 3 3 3 4 0 0 3 0 3 3 3 0 3 1 1 3 6 0 0 1 -1 0 1 1 0 1 0 1 1 0 -1 1 0 -1 1 */