貌似好久没写总结了,都快不会写了。
懒得分成几篇了,就一起挤一挤吧。
另外, 这里有分开写的
http://blog.csdn.net/huyuncong?viewmode=contents
哈哈!
初步的叉积:
貌似最近才分清楚谁叉谁是正,以前都是推得=.=;
最好还是模块化,一般很多情况都是只要调用两个参数,但是一般还是写成四个参数的,这样还是有好处的。
int cross(point a, point b, point c, point d)
{
int x1 = b.x - a.x, y1 = b.y - a.y;
int x2 = d.x - c.x, y2 = d.y - c.y;
return x1 * y2 - x2 * y1;
}
至少外面就不要判精度了
int cross2(point a, point b, point c, point d)
{
double x1 = b.x - a.x, y1 = b.y - a.y;
double x2 = d.x - c.x, y2 = d.y - c.y;
double k = x1 * y2 - x2 * y1;
if (k > eps) return 1;
else if (k < -eps) return -1;
else return 0;
}
叉积的线段相交, 排斥试验也是必不可少的=.=(这样就丑死了)
bool checkpoint(point a, point b, point c, point d) { if (max(a.x, b.x) >= min(c.x, d.x) &max(a.y, b.y) >= min(c.y, d.y) &max(c.x, d.x) >= min(a.x, b.x) &max(c.y, d.y) >= min(a.y, b.y) &cross(a, b, a, c) * cross(a, b, a, d)<= 0 &cross(d, c, d, a) * cross(d, c, d, b)<= 0) return true; else return false; }
line getline(point s, point t) { line gl; if (s.x == t.x) gl.b = 0, gl.a = 1, gl.c = - s.x; else if (s.y == t.y) gl.b = 1, gl.a = 0, gl.c = - s.y; else gl.a = 1, gl.b = (s.x - t.x) / (t.y - s.y), gl.c = -(s.x + gl.b * s.y); return gl; } point findpoint(line g1, line g2) { point p; p.y = - (g1.c - g2.c) / (g1.b - g2.b); p.x = - (g1.b * p.y + g1.c); return p; }
当然, 还是射影坐标系方便, 表示直线时就没有各种特殊情况了。
http://wenku.baidu.com/view/9f9a78c55fbfc77da269b172.html
line getline(point a, point b)
{
line g;
g.x = a.y * b.z - a.z * b.y;
g.y = a.z * b.x - a.x * b.z;
g.z = a.x * b.y - a.y * b.x;
double low = sqrt(sqr(g.x) + sqr(g.y));
g.x /= low; g.y /= low; g.z /= low;
return g;
}
point getpoint(line a, line b)
{
point g;
g.x = a.y * b.z - a.z * b.y;
g.y = a.z * b.x - a.x * b.z;
g.z = a.x * b.y - a.y * b.x;
if (! bezero(g.z))
g.x /= g.z; g.y /= g.z; g.z = 1;
return g;
}
两点叉积是直线,两线叉积是交点,至于点在线上,线过点,用点积就可以了。(how beautiful)
知道了叉积总的用用吧;
那就极角排序吧, 想了一堆办法来避免判象限,最终还是投降了(老老实实写象限吧)
int where(line a) { if (a.x < -eps & a.y < eps) return 1; if (a.x > eps & a.y > -eps) return 3; if (a.x > -eps & a.y < -eps) return 2; return 4; } bool checks(line a, line b) { int ka = where(a), kb = where(b); if (ka > kb) return false; if (ka < kb) return true; int k = cross2(lin[0], a, lin[0], b); if (k > 0) return true; if (k < 0) return false; if (a.d - b.d < -eps ) return true; return false; } void sort(int l , int r) { int i = l, j = r; line tmp, g = lin[(l + r)>> 1]; for (;i <= j;) { for (;checks(lin[i],g); i++); for (;checks(g,lin[j]); j--); if (i <= j) tmp = lin[i], lin[i] = lin[j], lin[j] =tmp, i++, j--; } if (l < j) sort(l, j); if (i < r) sort(i, r); }
凸包是老早就写过了的水平序graham
void work() { sort(1, n); top = 1; st[1] = 1; for (i = 2; i <= n; i++) { for (; top > 1 & cross(a[st[top-1]], a[i], a[st[top-1]], a[st[top]]) <= 0; top--); st[++top] = i; } int k = top; for (i = n-1; i >= 1; i--) { for (; top > k & cross(a[st[top-1]], a[i], a[st[top-1]], a[st[top]]) <= 0; top--); st[++top] = i; } top--; }
事先排过序的。总感觉很丑很丑........
用凸包干啥nian, 旋转卡壳蛮不错的:
(这个还是贴题目吧)
最远点对:
# include <cstdio> # include <cstdlib> # include <cstring> struct point { long long x, y; }; const int maxn = 100000 + 5; int i, n, top; long long ans; point a[maxn]; int st[maxn]; using namespace std; inline long long max(long long a, long long b) { return a > b? a : b; } inline long long cross(point a, point b, point c, point d) { long long x1 = b.x - a.x, y1 = b.y - a.y; long long x2 = d.x - c.x, y2 = d.y - c.y; return x1 * y2 - x2 * y1; } inline long long sqr(long long a) { return a * a; } inline long long dist(point a, point b) { return (sqr(a.x - b.x) + sqr(a.y - b.y)); } void sort(int l, int r) { int i = l, j = r; point tmp, g = a[(l + r) >> 1]; for (;i <= j;) { for (; a[i].y < g.y ||(a[i].y == g.y & a[i].x < g.x); i++); for (; a[j].y > g.y ||(a[j].y == g.y & a[j].x > g.x); j--); if (i <= j) tmp = a[i], a[i] = a[j], a[j] = tmp, i++, j--; } if (i < r) sort(i, r); if (l < j) sort(l, j); } void prepare() { sort(1, n); st[1] = 1; st[2] = 2; top = 2; int i; for (i = 3; i <= n; i++) { for (;top > 1 & cross(a[st[top - 1]], a[i], a[st[top - 1]], a[st[top]]) <= 0; top --); st[++top] = i; } int k = top; for (i = n - 1; i >= 1; i--) { for (;top > k & cross(a[st[top - 1]], a[i], a[st[top - 1]], a[st[top]]) <= 0; top --); st[++top] = i; } } void work() { top --; int j = 2; for (i = 1; i <= top; i++) { for (;cross(a[st[i]], a[st[j]], a[st[i]], a[st[i + 1]]) < cross(a[st[i]], a[st[j + 1]], a[st[i]], a[st[i + 1]]);) {j++; if (j > top) j = 1;} ans = max(ans, dist(a[st[i]], a[st[j]])); } } int main() { freopen("2187.in", "r", stdin); freopen("2187.out", "w", stdout); scanf("%d", &n); int i; for (i = 1; i <= n; i++) scanf("%I64d%I64d", &a[i].x , &a[i].y); prepare(); if (top == 2) { printf("%d", 0); return 0;} if (top == 3) { printf("%I64d", dist(a[st[1]], a[st[2]])); return 0;} work(); printf("%I64d", ans); return 0; }
最大三角形距离:
# include <cstdio> # include <cstdlib> # include <cstring> struct point { int x, y; }; const int maxn = 100000; int ans, k, i, j, n, top; point a[maxn]; int st[maxn]; int cross(point a, point b, point c, point d) { int x1 = b.x - a.x, y1 = b.y - a.y; int x2 = d.x - c.x, y2 = d.y - c.y; return x1 * y2 - x2 * y1; } int max(int a, int b) { return a > b? a: b; } void sort(int l, int r) { int i = l, j = r; point tmp, g = a[(l + r) >> 1]; for (;i <= j;) { for (;a[i].y < g.y || (a[i].y == g.y & a[i].x < g.x);i++); for (;a[j].y > g.y || (a[j].y == g.y & a[j].x > g.x);j--); if (i <= j) tmp = a[i], a[i] = a[j], a[j] = tmp, i++, j--; } if (i < r) sort(i, r); if (l < j) sort(l, j); } void work() { sort(1, n); top = 1; st[1] = 1; for (i = 2; i <= n; i++) { for (; top > 1 & cross(a[st[top-1]], a[i], a[st[top-1]], a[st[top]]) <= 0; top--); st[++top] = i; } int k = top; for (i = n-1; i >= 1; i--) { for (; top > k & cross(a[st[top-1]], a[i], a[st[top-1]], a[st[top]]) <= 0; top--); st[++top] = i; } top--; } void find_max() { for (i = 1; i <= top; i++) { k = i + 2; if (k > top) k -= top; for (j = i + 1; j <= top; j++) { for (;abs(cross(a[st[i]], a[st[j]], a[st[i]], a[st[k+1]])) > abs(cross(a[st[i]], a[st[j]], a[st[i]], a[st[k]]));) { k++; if (k > top) k -= top;} ans = max(ans, abs(cross(a[st[i]], a[st[j]], a[st[i]], a[st[k]]))); } } double p = ans/ 2.0; ans = 0; printf("%.2lf\n", p); } int main() { freopen("2079.in", "r", stdin); freopen("2079.out", "w", stdout); ans = 0; for (;;) { scanf("%d", &n); if (n == -1) return 0; memset(a, 0, sizeof(a)); memset(st, 0, sizeof(st)); for (i = 1; i <= n; i++) scanf("%d%d", &a[i].x, &a[i].y); work(); find_max(); } return 0; }
当然,对于凸包间的最短距离,是可以用Minkowski和做的(注意: 闵可夫斯基 貌似不是俄国人, 是德国人)
Minkowski和 就是把两个凸包按同一方向的向量排序后,依次连接, 得到一个大凸包;
容易理解,若对于凸包A,B: A+B={(xiA+xjB,yiA+yjB):(xiA,yiA )∈A,(xjB,yjB)∈B} 的凸包就是Minkowski和在平移一下就行了;
集训队那道题瞬间水了......
area:
# include <cstdio> # include <cstdlib> # include <cstring> using namespace std; struct point { long long x, y; }; const int maxn = 500000; int top, i, j, n, m, topa, topb; point a[maxn], b[maxn], sd[maxn]; int sta[maxn], stb[maxn]; long long ans; long long cross(point a, point b, point c, point d) { long long x1 = b.x - a.x, y1 = b.y - a.y; long long x2 = d.x - c.x, y2 = d.y - c.y; return x1 * y2 - x2 * y1; } void sort(point *c, int l, int r) { int i = l, j = r; point tmp, g = c[l + rand() % (r - l + 1)]; for (; i <= j;) { for (; c[i].y < g.y || (c[i].y == g.y & c[i].x < g.x); i++); for (; c[j].y > g.y || (c[j].y == g.y & c[j].x > g.x); j--); if (i <= j) tmp = c[i], c[i] = c[j], c[j] = tmp, i++, j--; } if (i < r) sort (c, i, r); if (l < j) sort (c, l, j); } void work(point *c, int n, int *stc, int &topc) { topc = 1, stc[1] = 1; for (i = 2; i <= n; i++) { for (;topc > 1 & cross(c[stc[topc - 1]], c[i], c[stc[topc - 1]], c[stc[topc]]) <= 0;topc--); stc[++topc] = i; } int k = topc; for (i = n - 1; i >= 1; i--) { for (;topc > k & cross(c[stc[topc - 1]], c[i], c[stc[topc - 1]], c[stc[topc]]) <= 0;topc--); stc[++topc] = i; } } int got(point a, point b) { int x1 = b.x - a.x, y1 = b.y - a.y; if (x1 < 0 & y1 <= 0) return 1; if (x1 >= 0 & y1 < 0) return 2; if (x1 > 0 & y1 >= 0) return 3; /*if (x1 <= 0 & y1 > 0)*/ return 4; } bool checks (point a, point b, point c, point d) { int k1 = got(a, b); int k2 = got(c, d); if (k1 < k2) return true; if (k1 > k2) return false; if (cross(a, b, c, d) > 0) return true; return false; } void sort2(int l, int r) { int i = l, j = r; point tmp, g = sd[l + rand()% (r - l + 1)]; for (; i <= j;) { for (; checks(sd[0], sd[i], sd[0], g) ; i++); for (; checks(sd[0], g, sd[0], sd[j]) ; j--); if (i <= j) tmp = sd[i], sd[i] = sd[j], sd[j] = tmp, i++, j--; } if (i < r) sort2 (i, r); if (l < j) sort2 (l, j); } int main() { freopen("area.in", "r", stdin); freopen("area.out", "w", stdout); scanf("%d%d", &n, &m); for (i = 1; i <= n; i++) scanf("%I64d%I64d", &a[i].x, &a[i].y); for (i = 1; i <= m; i++) scanf("%I64d%I64d", &b[i].x, &b[i].y); sort (a, 1, n); work(a, n, sta, topa); sort (b, 1, m); work(b, m, stb, topb); top = 0; for (i = 1; i <= topa -1; i++) sd[++top].x = a[sta[i + 1]].x - a[sta[i]].x, sd[top].y = a[sta[i + 1]].y - a[sta[i]].y; for (i = 1; i <= topb -1; i++) sd[++top].x = b[stb[i + 1]].x - b[stb[i]].x, sd[top].y = b[stb[i + 1]].y - b[stb[i]].y; sd[0].x = 0; sd[0].y = 0; sort2(1, top); long long dx = 0, dy = 0, ex = 0, ey = 0; for (i = 1; i <= top; i++) { ex = dx + sd[i].x; ey = dy + sd[i].y; ans += dx * ey - ex * dy; dx = ex; dy = ey; } if (ans < 0) ans = -ans; printf("%I64d", ans); return 0; }
令-B 就是B点集的每一个点的坐标都取反,那么Minkowski差就可以求凸包最近点:
求出A-B, 平移后,距离原点的距离就是凸包间最短距离了。
最后还剩半平面交;
zzy的s&l 还是挺容易写的,除了还不是很理解;
主要思路是用双端队列维护,按极角序插入,进队列前判断如果前两个或后两个半平面的交点在要插入的
半平面外,就往里踢。
只是还有一些题目死活过不了+.+!
判不等式组是否有解:poj1755
# include <cstdio> # include <cstdlib> # include <cstring> # include <cmath> using namespace std; struct line { double x, y, z, d; }; struct point { double x, y, z; }; int t; const int maxn = 200; line ll[maxn], lin[maxn], ask[maxn]; int n, tot, que[maxn]; const double eps = 1e-18, oo = 1073741819.1; double low; bool bezero(double x) { return x > -eps & x < eps ? true: false; } double sqr(double x) { return x*x; } int cross2(line a, line b, line c, line d) { double x1 = b.x - a.x, y1 = b.y - a.y; double x2 = d.x - c.x, y2 = d.y - c.y; double k = x1 * y2 - x2 * y1; if (k > eps) return 1; else if (k < -eps) return -1; else return 0; } double abs(double x) { return x < 0? -x : x; } point cross(line a, line b) { point g; g.x = a.y * b.z - a.z * b.y; g.y = a.z * b.x - a.x * b.z; g.z = a.x * b.y - a.y * b.x; if (! bezero(g.z)) g.x /= g.z, g.y /=g.z, g.z = 1; return g; } int where(line a) { if (a.x < -eps & a.y < eps) return 1; if (a.x > eps & a.y > -eps) return 3; if (a.x > -eps & a.y < -eps) return 2; return 4; } bool checks(line a, line b) { int ka = where(a), kb = where(b); if (ka > kb) return false; if (ka < kb) return true; int k = cross2(lin[0], a, lin[0], b); if (k > 0) return true; if (k < 0) return false; if (a.d - b.d < -eps ) return true; return false; } void sort(int l , int r) { int i = l, j = r; line tmp, g = lin[(l + r)>> 1]; for (;i <= j;) { for (;checks(lin[i],g); i++); for (;checks(g,lin[j]); j--); if (i <= j) tmp = lin[i], lin[i] = lin[j], lin[j] =tmp, i++, j--; } if (l < j) sort(l, j); if (i < r) sort(i, r); } bool stayin(line a, point b) { if (bezero(b.z)) return false; if (b.x * a.x + b.y * a.y + a.z > eps) return true; return false; } bool check() { lin[++tot].x = 0, lin[tot].y = 1, lin[tot].z = 0; lin[++tot].x = 1, lin[tot].y = 0, lin[tot].z = 0; lin[++tot].x = -1, lin[tot].y = 0, lin[tot].z = oo; lin[++tot].x = 0, lin[tot].y = -1, lin[tot].z = oo; sort (1, tot); int i, l = 1, r = 1; que[1] = 1; memset(ll, 0, sizeof(ll)); t = 1; for (i = 2;i <= tot; i++) if (! bezero(lin[i].x * lin[i-1].y - lin[i-1].x * lin[i].y)) { for (; (r - l) > 0 & (!stayin(lin[i], cross(lin[que[r]], lin[que[r-1]]))); r--); for (; (r - l) > 0 & (!stayin(lin[i], cross(lin[que[l]], lin[que[l+1]]))); l++); que[++r] = i; } for (; (r - l) > 0 & (!stayin(lin[que[l]], cross(lin[que[r]], lin[que[r-1]]))); r--); for (; (r - l) > 0 & (!stayin(lin[que[r]], cross(lin[que[l]], lin[que[l+1]]))); l++); if (r - l >= 2) return true; else return false; } int main() { int i, j; freopen("1755.in", "r", stdin); freopen("1755.out", "w", stdout); scanf("%d", &n); for (i = 1; i <= n; i++) scanf("%lf%lf%lf", &ask[i].x, &ask[i].y, &ask[i].z); for (i = 1; i <= n; i++) { tot = 0; bool flag = false; memset(lin, 0, sizeof(lin)); memset(que, 0, sizeof(que)); for (j = 1; j <= n; j++) if (i != j) { if (ask[j].x-ask[i].x >-eps & ask[j].y-ask[i].y>-eps & ask[j].z -ask[i].z>-eps) flag = true; tot++; lin[tot].x = (ask[i].x - ask[j].x)/(ask[i].x*ask[j].x); //1 / ask[j].x - 1 / ask[i].x; lin[tot].y = (ask[i].y - ask[j].y)/(ask[i].y*ask[j].y);//1 / ask[j].y - 1 / ask[i].y; lin[tot].z = (ask[i].z - ask[j].z)/(ask[i].z*ask[j].z);//1 / ask[j].z - 1 / ask[i].z; low = sqrt(sqr(lin[tot].x) + sqr(lin[tot].y)); lin[tot].d = lin[tot].z / low; } if (flag) printf("No\n"); else if (check()) printf("Yes\n"); else printf("No\n"); } return 0; }
# include <cstdio> # include <cstdlib> # include <cmath> # include <cstring> using namespace std; struct line { double x, y, z; }; struct point { double x, y, z; }; const int maxn = 200; const double eps = 1e-6; line lin[maxn]; point a[maxn]; int que[maxn]; double tx = 0, ty = 0; int l, r, n; bool bezero(double x) { return x < eps & x > -eps ?true: false; } double sqr(double x) { return x * x; } line getline(point a, point b) { line g; g.x = a.y * b.z - a.z * b.y; g.y = a.z * b.x - a.x * b.z; g.z = a.x * b.y - a.y * b.x; double low = sqrt(sqr(g.x) + sqr(g.y)); g.x /= low; g.y /= low; g.z /= low; return g; } point getpoint(line a, line b) { point g; g.x = a.y * b.z - a.z * b.y; g.y = a.z * b.x - a.x * b.z; g.z = a.x * b.y - a.y * b.x; if (! bezero(g.z)) g.x /= g.z; g.y /= g.z; g.z = 1; return g; } int cross2(line a, line b, line c, line d) { double x1 = b.x - a.x, y1 = b.y - a.y; double x2 = d.x - c.x, y2 = d.y - c.y; double g = x1 * y2 - x2 * y1; if (g < -eps) return -1; if (g > eps) return 1; return 0; } int where(line a) { if (a.x < -eps & a.y < eps) return 1; if (a.x > -eps & a.y < -eps) return 2; if (a.x > eps & a.y > -eps) return 3; return 4; } bool checks(line a, line b) { int ka = where(a), kb = where(b); if (ka < kb) return true; if (ka > kb) return false; int g = cross2(lin[0], a, lin[0], b); if (g > 0) return true; if (g < 0) return false; if (a.z - b.z < -eps) return true; return false; } void sort(int l, int r) { int i = l, j = r; line tmp, g = lin[(l + r) >> 1]; for (;i <= j;) { for (;checks(lin[i],g);i++); for (;checks(g,lin[j]);j--); if (i <= j) tmp = lin[i], lin[i] = lin[j], lin[j] = tmp, i++, j--; } if (i < r) sort(i, r); if (l < j) sort(l, j); } void prepare() { int i; memset(a, 0, sizeof(a)); tx = 0; ty = 0; //scanf("%d", &n); for (i = n; i >= 1; i--) { scanf("%lf%lf", &a[i].x, &a[i].y); a[i].z = 1; } memset(lin, 0, sizeof(lin)); a[n+1] = a[1]; for (i = 1; i <= n; i++) lin[i] = getline(a[i], a[i + 1]); for (i = 1; i <= n; i++) { point k; k.x = a[i+1].x - a[i].x; k.y = a[i+1].y - a[i].y; a[i].z = 1; if (k.x * lin[i].y - k.y * lin[i].x > eps) lin[i].x = -lin[i].x, lin[i].y = -lin[i].y, lin[i].z = -lin[i].z; } sort(1, n); } bool stayin(line a, point b) { return a.x * b.x + a.y * b.y + a.z < eps || bezero(b.z)? false: true; } void proce() { int i; prepare(); memset(que, 0, sizeof(que)); l = 1; r = 1; que[1] = 1; for (i = 2; i <= n; i++) if (! bezero(lin[i].x * lin[i-1].y - lin[i-1].x * lin[i].y)) { for (;r > l & (!stayin(lin[i], getpoint(lin[que[r]], lin[que[r-1]]))); r--); for (;r > l & (!stayin(lin[i], getpoint(lin[que[l]], lin[que[l+1]]))); l++); que[++r] = i; } for (;r > l & (!stayin(lin[que[l]], getpoint(lin[que[r]], lin[que[r-1]]))); r--); for (;r > l & (!stayin(lin[que[r]], getpoint(lin[que[l]], lin[que[l+1]]))); l++); if (r - l >= 2) printf("1\n"); else printf("0\n"); } int main() { int t, i; freopen("3130.in", "r", stdin); freopen("3130.out", "w", stdout); for (;;) { scanf("%d", &n); if (n == 0) break; proce(); } return 0; }