貌似好久沒寫總結了,都快不會寫了。
懶得分成幾篇了,就一起擠一擠吧。
另外, 這裏有分開寫的
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);
}
純手工打造快排,不要bs;
凸包是老早就寫過了的水平序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;
}
旋轉卡殼什麼的,原來是沒有直線的,只是用叉積判了一下方向而已,(how beautiful ,too)
當然,對於凸包間的最短距離,是可以用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;
}
多邊形的核:poj3130
# 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;
}