貌似好久没写总结了,都快不会写了。
懒得分成几篇了,就一起挤一挤吧。
另外, 这里有分开写的
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;
}