【计算几何】计算几何复习

时间:2023-02-10 17:22:40

点,线,面,形基本关系,点积叉积的理解

poj2318 TOYS

/****************************\
* @prob: poj2318 TOYS *
* @auth: Wang Junji *
* @stat: Accepted. *
* @date: June. 25th, 2012 *
* @memo: 点和直线位置关系 *
\****************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 5010;
int cnt[maxN], lower[maxN], upper[maxN], n, m, X0, Y0, X1, Y1;

inline int Find(int x, int y)
{
int L = 0, R = n;
while (L < R)
{
int Mid = (L + R) >> 1;
double __x = (upper[Mid] - lower[Mid]) / double(Y1 - Y0) * (y - Y0) + lower[Mid];
if (__x < x) L = Mid + 1;
else R = Mid;
} /* while */
return R - 1;
} /* Find */

int main()
{
freopen("toys.in" , "r", stdin );
freopen("toys.out", "w", stdout);
while (~scanf("%d%d%d%d%d%d", &n, &m, &X0, &Y1, &X1, &Y0) && n)
{
++n; upper[0] = lower[0] = X0;
for (int i = 1; i < n; ++i)
scanf("%d%d", upper + i, lower + i);
lower[n] = upper[n] = X1;
memset(cnt, 0, sizeof cnt);
while (m--)
{
int x, y;
scanf("%d%d", &x, &y);
++cnt[Find(x, y)];
} /* while */
for (int i = 0; i < n; ++i)
printf("%d: %d\n", i, cnt[i]);
puts("");
} /* while */
return 0;
} /* main */

/*

用二分查找每个玩具所对应的分区即可。

*/
poj2398 Toy Storage

/*******************************\
* @prob: poj2398 Toy Storage *
* @auth: Wang Junji *
* @stat: Accepted. *
* @date: June. 25th, 2012 *
* @memo: 点和直线位置关系 *
\*******************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 1010;
int has[maxN], cnt[maxN], lower[maxN], upper[maxN], n, m, X0, Y0, X1, Y1;

inline int Find(int x, int y)
{
int L = 0, R = n;
while (L < R)
{
int Mid = (L + R) >> 1;
double __x = (upper[Mid] - lower[Mid]) / double(Y1 - Y0) * (y - Y0) + lower[Mid];
if (__x < x) L = Mid + 1;
else R = Mid;
} /* while */
return R - 1;
} /* Find */

int main()
{
freopen("Toy_Storage.in" , "r", stdin );
freopen("Toy_Storage.out", "w", stdout);
while (~scanf("%d%d%d%d%d%d", &n, &m, &X0, &Y1, &X1, &Y0) && n)
{
++n; upper[0] = lower[0] = X0;
for (int i = 1; i < n; ++i)
scanf("%d%d", upper + i, lower + i);
lower[n] = upper[n] = X1;
std::sort(lower, lower + n);
std::sort(upper, upper + n);
memset(cnt, 0, sizeof cnt);
memset(has, 0, sizeof has);
while (m--)
{
int x, y;
scanf("%d%d", &x, &y);
++has[Find(x, y)];
} /* while */
puts("Box");
for (int i = 0; i < n; ++i) ++cnt[has[i]];
for (int i = 1; i < n; ++i)
if (cnt[i]) printf("%d: %d\n", i, cnt[i]);
} /* while */
return 0;
} /* main */

/*

用二分查找每个玩具所对应的分区即可。

*/
视野动态规划

poj1556 The Doors

/*****************************\
* @prob: poj1556 The Doors *
* @auth: Wang Junji *
* @stat: Accepted. *
* @date: June. 25th. 2012 *
* @memo: 视野动态规划 *
\*****************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>

const int maxN = 110;
const double INF = 1e198, zero = 1e-8;

struct vec
{
double x, y; vec() {} /* vec */
vec(const double& x, const double& y): x(x), y(y) {} /* vec */
vec(const vec& b): x(b.x), y(b.y) {} /* vec */
vec operator-(const vec& b) const
{return vec(x - b.x, y - b.y);}
/* operator- */
double operator*(const vec& b) const
{return x * b.y - y * b.x;}
/* operator* */
vec lwr() const {return vec(x, y - 1);} /* lwr */
vec upr() const {return vec(x, y + 1);} /* upr */
} p[maxN][4]; int n; double d[maxN][4];

template <typename _Tp>
inline _Tp& gmax(_Tp& a, const _Tp& b)
{return a > b ? a : (a = b);}
/* gmax */

template <typename _Tp>
inline _Tp& gmin(_Tp& a, const _Tp& b)
{return a < b ? a : (a = b);}
/* gmin */

template <typename _Tp> inline _Tp sqr(const _Tp& x) {return x * x;} /* sqr */

inline
bool check(const vec& lwr, const vec& upr,
const vec& st , const vec& ed)
{
if (st.x - ed.x > -zero) return false;
if ((ed - st) * (lwr - st) > zero) return false;
if ((upr - st) * (ed - st) > zero) return false;
return true;
} /* check */

inline double dist(const vec& a, const vec& b)
{return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));}
/* dist */

inline
void work(const double& val,
const vec& lwr,
const vec& upr,
const vec& st,
const int& i)
{
if (val - INF > -zero) return;
if (d[n][0] - 10 < zero) return;
if (i == n && check(lwr, upr, st, p[n][0]))
gmin(d[n][0], val + dist(st, p[n][0]));
for (int j = 0; j < 4; ++j)
if (check(lwr, upr, st, p[i][j]))
gmin(d[i][j], val + dist(st, p[i][j]));
vec __lwr(lwr), __upr(upr);
bool ch_lwr = check(lwr, upr, st, p[i][0]),
ch_upr = check(lwr, upr, st, p[i][1]);
if (ch_lwr) __lwr = p[i][0];
if (ch_upr) __upr = p[i][1];
if (__lwr * __upr > zero && (ch_lwr || ch_upr))
work(val, __lwr, __upr, st, i + 1);
__lwr = lwr, __upr = upr;
ch_lwr = check(lwr, upr, st, p[i][2]);
ch_upr = check(lwr, upr, st, p[i][3]);
if (ch_lwr) __lwr = p[i][2];
if (ch_upr) __upr = p[i][3];
if (__lwr * __upr > zero && (ch_lwr || ch_upr))
work(val, __lwr, __upr, st, i + 1);
return;
} /* work */

int main()
{
freopen("door.in" , "r", stdin );
freopen("door.out", "w", stdout);
while (~scanf("%d", &n) && ~n)
{
p[0][0] = vec(0., 5.); ++n;
for (int i = 1; i < n; ++i)
{
double x, y0, y1, y2, y3;
scanf("%lf%lf%lf%lf%lf", &x, &y0, &y1, &y2, &y3);
p[i][0] = vec(x, y0);
p[i][1] = vec(x, y1);
p[i][2] = vec(x, y2);
p[i][3] = vec(x, y3);
d[i][0] = d[i][1] = d[i][2] = d[i][3] = INF;
} /* for */
p[n][0] = vec(10., 5.); d[n][0] = INF;
work(0, p[0][0].lwr(), p[0][0].upr(), p[0][0], 1);
for (int i = 1; i < n; ++i)
for (int j = 0; j < 4; ++j)
work(d[i][j], p[i][j].lwr(), p[i][j].upr(), p[i][j], i + 1);
printf("%.2lf\n", d[n][0]);
} /* while */
return 0;
} /* main */

/*

维护视野的上界和下界,然后依次松弛每个点即可。

*/
凸包、旋转卡壳

UVa681 Convex Hull Finding

/**************************************\
* @prob: UVa681 Convex Hull Finding *
* @auth: Wang Junji *
* @stat: Accepted. *
* @date: June. 26th, 2012 *
* @memo: 凸包 *
\**************************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

int const maxN = 520;
struct vec
{
int x, y; vec() {} /* vec */ vec(int x, int y): x(x), y(y) {} /* vec */
vec operator-(const vec& b) const {return vec(x - b.x, y - b.y);} /* operator- */
int operator*(const vec& b) const {return x * b.y - y * b.x; } /* operator- */
} p[maxN], res[maxN];
int n, T;

inline vec const*
Granham(vec const* const __fir, vec const* const __la, vec* res)
{
vec* tmp = res + 1; vec const* fir = __fir;
if (fir == __la) return res;
*res++ = *fir++; if (fir == __la) return res;
*res++ = *fir++; if (fir == __la) return res;
for (; fir != __la; *res++ = *fir++)
while (res != tmp && (fir[0] - res[-1]) * (res[-1] - res[-2]) >= 0)
--res;
tmp = res; *res++ = __la[-2];
for (fir = __la - 2; fir-- != __fir; *res++ = *fir)
while (res != tmp && (fir[0] - res[-1]) * (res[-1] - res[-2]) >= 0)
--res;
return res;
} /* Granham */

inline bool cmp(vec const& a, vec const& b)
{return a.y < b.y || (a.y == b.y && a.x < b.x);}
/* cmp */

int main()
{
freopen("Convex_Hull.in" , "r", stdin );
freopen("Convex_Hull.out", "w", stdout);
for (scanf("%d", &T), printf("%d\n", T); T--; ~scanf("\n-1") && puts("-1"))
{
scanf("%d", &n);
for (int i = 0; i < n; ++i)
scanf("%d%d", &p[i].x, &p[i].y);
std::sort(p, p + n, cmp);
n = Granham(p, p + n, res) - res;
printf("%d\n", n);
for (int i = 0; i < n; ++i)
printf("%d %d\n", res[i].x, res[i].y);
} /* for */
return 0;
} /* main */

/*

凸包的模板题,不再多说。

*/
poj2187 Beauty Contest

/**********************************\
* @prob: poj2187 Beauty Contest *
* @auth: Wang Junji *
* @stat: Accepted. *
* @date: June. 28th, 2012 *
* @memo: 旋转卡壳 *
\**********************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 50010;

struct vec
{
int x, y; vec() {} /* vec */ vec(int x, int y): x(x), y(y) {} /* vec */
vec operator-(const vec& b) const {return vec(x - b.x, y - b.y);} /* operator- */
int operator*(const vec& b) const {return x * b.y - y * b.x;} /* operator* */
int sqrabs() const {return x * x + y * y;}
} p[maxN], res[maxN]; int n;

inline int& gmax(int& a, const int& b) {return a > b ? a : (a = b);} /* gmax */

inline bool cmp(const vec& a, const vec& b)
{return a.y < b.y || (a.y == b.y && a.x < b.x);}
/* cmp */

inline const vec*
Granham(const vec* const __fir, const vec* const __la, vec* res)
{
const vec* fir = __fir;
const vec* tmp = res + 1;
for (*res++ = *fir++, *res++ = *fir++; fir != __la; *res++ = *fir++)
while (res != tmp && (fir[0] - res[-1]) * (res[-1] - res[-2]) >= 0)
--res;
tmp = res; *res++ = __la[-2];
for (fir = __la - 2; fir-- != __fir; *res++ = *fir)
while (res != tmp && (fir[0] - res[-1]) * (res[-1] - res[-2]) >= 0)
--res;
return res - 1;
} /* Granham */

int main()
{
freopen("Beauty.in" , "r", stdin );
freopen("Beauty.out", "w", stdout);
scanf("%d", &n);
for (int i = 0; i < n; ++i)
scanf("%d%d", &p[i].x, &p[i].y);
std::sort(p, p + n, cmp);
n = Granham(p, p + n, res) - res;
int ans = 0;
for (const vec *ths = res, *oppo = res + 2; ths != res + n; ++ths)
//注意这里oppo必须从res + 2开始枚举,否则错。
{
while ((oppo[1] - ths[0]) * (oppo[1] - ths[1])
> (oppo[0] - ths[0]) * (oppo[0] - ths[1]))
if (++oppo == res + n) oppo = res;
gmax(ans, (*oppo - *ths).sqrabs());
} /* for */
printf("%d\n", ans); return 0;
} /* main */

/*

旋转卡壳模板题,不再多说。

*/
半平面交

poj2451 Uyuw's Concert

/**********************************\
* @prob: poj2451 Uyuw's Concert *
* @auth: Wang Junji *
* @stat: Accepted. *
* @date: June. 26th. 2012 *
* @memo: 半平面交 *
\**********************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <deque>

using std::deque;
typedef double DBL;
const int maxN = 20010;
const DBL zero = 1e-12L;

struct vec
{
DBL x, y; vec() {} /* vec */ vec(DBL x, DBL y): x(x), y(y) {} /* vec */
vec operator-(const vec& b) const {return vec(x - b.x, y - b.y);} /* operator- */
vec operator+(const vec& b) const {return vec(x + b.x, y + b.y);} /* operator+ */
vec operator*(const DBL& t) const {return vec(x * t, y * t);} /* operator* */
DBL operator*(const vec& b) const {return x * b.y - y * b.x;} /* operator* */
} p[maxN];

struct HP
{
vec A, B; DBL ang; HP() {} /* HP */
HP(const vec& A, const vec& B): A(A), B(B)
{ang = atan2(B.y - A.y, B.x - A.x);}
/* HP */
} hp[maxN]; int n;

inline int sgn(const DBL& x) {return x < -zero ? -1 : x > zero ? 1 : 0;} /* sgn */
inline DBL sqr(const DBL& x) {return x * x;} /* sqr */
inline bool eql(const HP& a, const HP& b) {return !sgn(a.ang - b.ang);} /* eql */
inline bool notin(const vec& P, const HP& a) {return (P - a.B) * (P - a.A) > -zero;} /* notin */

inline int cmp(const void* __a, const void* __b)
{
const HP &a = *(HP*)__a, &b = *(HP*)__b;
int tmp = sgn(a.ang - b.ang);
if (tmp) return tmp;
return sgn((b.B - a.A) * (b.A - a.A));
} /* cmp */

inline vec cross(const HP& a, const HP& b)
{
vec AB = a.B - a.A, CD = b.B - b.A,
AC = b.A - a.A, AD = b.B - a.A;
return a.A + AB * ((AC * AD) / (AB * CD));
} /* cross */

inline const deque <HP>&
Half_Plane_Inter(const HP* fir, const HP* la)
{
static deque <HP> q; q.clear();
for (q.push_back(*fir++), q.push_back(*fir++); fir != la; q.push_back(*fir++))
{
while (q.size() > 1 && notin(cross(*(q.end() - 2), q.back()), *fir)) q.pop_back();
while (q.size() > 1 && notin(cross(q.front(), *(q.begin() + 1)), *fir)) q.pop_front();
} /* for */
for (;;)
{
bool flag = 0;
while (q.size() > 2 && notin(cross(*(q.end() - 2), q.back()), q.front()))
q.pop_back(), flag = 1;
while (q.size() > 2 && notin(cross(q.front(), *(q.begin() + 1)), q.back()))
q.pop_front(), flag = 1;
if (!flag) break;
} /* for */
return q;
} /* Half_Plane_Inter */

int main()
{
freopen("Concert.in" , "r", stdin );
freopen("Concert.out", "w", stdout);
scanf("%d", &n);
for (int i = 0; i < n; ++i)
{
DBL x1, y1, x2, y2;
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
hp[i] = HP(vec(x1, y1), vec(x2, y2));
} /* for */
hp[n++] = HP(vec(0 , 0 ), vec(1e4, 0 ));
hp[n++] = HP(vec(1e4, 0 ), vec(1e4, 1e4));
hp[n++] = HP(vec(1e4, 1e4), vec(0 , 1e4));
hp[n++] = HP(vec(0 , 1e4), vec(0 , 0 ));
qsort(hp, n, sizeof hp[0], cmp);
n = std::unique(hp, hp + n, eql) - hp;
deque <HP> res = Half_Plane_Inter(hp, hp + n);
if (res.size() < 3) printf("0.0\n");
else
{
n = 0;
p[n++] = cross(res.front(), res.back());
for (deque <HP>::const_iterator iter = res.begin(); iter + 1 != res.end(); ++iter)
p[n++] = cross(*iter, *(iter + 1));
DBL ans = 0;
for (int i = 1; i + 1 < n; ++i)
ans += fabs((p[i + 1] - p[0]) * (p[i] - p[0]));
printf("%.1lf\n", ans /= 2);
} /* else */
return 0;
} /* main */

/*

半平面交的模板题。
注意不能使用long double类型,否则超时。

*/
poj3384 Feng Shui

/*****************************\
* @prob: poj3384 Feng Shui *
* @auth: Wang Junji *
* @stat: Accepted. *
* @date: June. 28th, 2012 *
* @memo: 半平面交 *
\*****************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <deque>
#include <cmath>

using std::deque;
const int maxN = 210;
const double zero = 1e-10;

struct vec
{
double x, y; vec() {} /* vec */ vec(double x, double y): x(x), y(y) {} /* vec */
vec operator-(const vec& b) const {return vec(x - b.x, y - b.y);} /* operator- */
vec operator+(const vec& b) const {return vec(x + b.x, y + b.y);} /* operator+ */
vec operator*(const double& t) const {return vec(x * t, y * t);} /* operator* */
double operator*(const vec& b) const {return x * b.y - y * b.x;} /* operator* */
double abs() const {return sqrt(x * x + y * y);} /* abs */
} p[maxN];

struct HP
{
vec A, B; double ang; HP() {} /* HP */
HP(const vec& A, const vec& B): A(A), B(B) {ang = atan2(B.y - A.y, B.x - A.x);} /* HP */
void mv(const double& r)
{
double d = (B - A).abs(), x1 = A.x, x2 = B.x, y1 = A.y, y2 = B.y;
A.x += (y1 - y2) * r / d;
B.x += (y1 - y2) * r / d;
A.y += (x2 - x1) * r / d;
B.y += (x2 - x1) * r / d;
} /* mv */
} hp[maxN]; double Rad; int n;

inline int sgn(const double& x) {return x < -zero ? -1 : x > zero ? 1 : 0;} /* sgn */

inline int cmp(const void* __a, const void* __b)
{
const HP &a = *(HP*)__a, &b = *(HP*)__b;
int tmp = sgn(a.ang - b.ang);
if (tmp) return tmp;
return sgn((b.B - a.A) * (b.A - a.A));
} /* cmp */

inline bool eql(const HP& a, const HP& b) {return !sgn(a.ang - b.ang);} /* eql */

inline vec cross(const HP& a, const HP& b)
{
vec AB = a.B - a.A, CD = b.B - b.A,
AC = b.A - a.A, AD = b.B - a.A;
return a.A + AB * ((AC * AD) / (AB * CD));
} /* cross */

inline bool outof(const vec& P, const HP& a)
{return (P - a.B) * (P - a.A) > zero;}
/* outof */
//这里不能排除三点共线的情况。

inline const deque <HP>&
Half_Plane_Inter(const HP* fir, const HP* la)
{
static deque <HP> q; q.clear();
for (q.push_back(*fir++), q.push_back(*fir++); fir != la; q.push_back(*fir++))
{
while (q.size() > 1 && outof(cross(*(q.end() - 2), q.back()) , *fir)) q.pop_back ();
while (q.size() > 1 && outof(cross(q.front(), *(q.begin() + 1)), *fir)) q.pop_front();
} /* for */
for (;;)
{
bool flag = 0;
while (q.size() > 2 && outof(cross(*(q.end() - 2), q.back()) , q.front()))
q.pop_back (), flag = 1;
while (q.size() > 2 && outof(cross(q.front(), *(q.begin() + 1)), q.back ()))
q.pop_front(), flag = 1;
if (!flag) break;
} /* for */
return q;
} /* Half_Plane_Inter */

int main()
{
freopen("Feng_Shui.in" , "r", stdin );
freopen("Feng_Shui.out", "w", stdout);
while (~scanf("%d%lf", &n, &Rad))
{
for (int i = 0; i < n; ++i)
scanf("%lf%lf", &p[i].x, &p[i].y);
p[n] = p[0];
for (int i = 0; i < n; ++i)
hp[i] = HP(p[i + 1], p[i]), hp[i].mv(Rad);
qsort(hp, n, sizeof hp[0], cmp);
n = std::unique(hp, hp + n, eql) - hp;
const deque <HP> res = Half_Plane_Inter(hp, hp + n);
if (res.size() < 3)
{
vec tmp = cross(hp[0], hp[1]);
printf("%.4lf %.4lf %.4lf %.4lf\n", tmp.x, tmp.y, tmp.x, tmp.y);
} /* if */
else
{
n = 0;
for (deque <HP>::const_iterator iter = res.begin(); iter + 1 != res.end(); ++iter)
p[n++] = cross(*iter, *(iter + 1));
p[n++] = cross(res.back(), res.front());
p[n] = p[0];
vec p1, p2;
double ans = 0;
for (int i = 0; i + 1 < n; ++i)
for (int j = i + 1; j < n; ++j)
{
double d = (p[i] - p[j]).abs();
if (d - ans > -zero) ans = d, p1 = p[i], p2 = p[j];
} /* for */
if (p1.x > p2.x) std::swap(p1, p2);
printf("%.4lf %.4lf %.4lf %.4lf\n", p1.x, p1.y, p2.x, p2.y);
} /* else */
} /* while */
return 0;
} /* main */

/*

这道题的Special Judge有点问题,需要注意:
1) 半平面交时不能排除三点共线的情况(这并不是Sepical Judge的问题,因为这样会排除可能的最优解);
2) 求最远点对时只能用枚举的方法,不能旋转卡壳;
3) 输出最后结果时,保证第一个点的横坐标小于第二个点;
4) 枚举最远点对时,若当前值大于等于最大值时更新,而不是大于。

还要注意半平面交为空的情况,这时候应当通过原始边来找到中间的唯一解。

*/
poj1279 Art Gallery

/*******************************\
* @prob: poj1279 Art Gallery *
* @auth: Wang Junji *
* @stat: Accepted. *
* @date: June. 28th, 2012 *
* @memo: 半平面交 *
\*******************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <deque>

using std::deque;
const int maxN = 1510;
const double zero = 1e-8;

struct vec
{
double x, y; vec() {} /* vec */ vec(double x, double y): x(x), y(y) {} /* vec */
vec operator-(const vec& b) const {return vec(x - b.x, y - b.y);} /* operator- */
vec operator+(const vec& b) const {return vec(x + b.x, y + b.y);} /* operator+ */
vec operator*(const double& t) const {return vec(x * t, y * t);} /* operator* */
double operator*(const vec& b) const {return x * b.y - y * b.x;} /* operator* */
} p[maxN];

struct HP
{
vec A, B; double ang; HP() {} /* HP */
HP(const vec& A, const vec& B): A(A), B(B)
{ang = atan2(B.y - A.y, B.x - A.x);} /* HP */
} hp[maxN];
int n, T;

inline int sgn(const double& x)
{return x < -zero ? -1 : x > zero ? 1 : 0;}
/* sgn */

inline bool eql(const HP& a, const HP& b) {return !sgn(a.ang - b.ang);} /* eql */

inline int cmp(const void* __a, const void* __b)
{
const HP &a = *(HP*)__a, &b = *(HP*)__b;
int tmp = sgn(a.ang - b.ang);
if (tmp) return tmp;
return sgn((b.B - a.A) * (b.A - a.A));
} /* cmp */

inline vec cross(const HP& a, const HP& b)
{
vec AB = a.B - a.A, CD = b.B - b.A,
AC = b.A - a.A, AD = b.B - a.A;
return a.A + AB * ((AC * AD) / (AB * CD));
} /* cross */

inline bool notin(const vec& P, const HP& a)
{return (P - a.B) * (P - a.A) > -zero;}
/* notin */

inline const deque <HP>&
Half_Plane_Inter(const HP* fir, const HP* la)
{
static deque <HP> q; q.clear();
for (q.push_back(*fir++), q.push_back(*fir++); fir != la; q.push_back(*fir++))
{
while (q.size() > 1 && notin(cross(*(q.end() - 2), q.back()) , *fir)) q.pop_back ();
while (q.size() > 1 && notin(cross(q.front(), *(q.begin() + 1)), *fir)) q.pop_front();
} /* for */
for (;;)
{
bool flag = 0;
while (q.size() > 2 && notin(cross(*(q.end() - 2), q.back()) , q.front()))
q.pop_back (), flag = 1;
while (q.size() > 2 && notin(cross(q.front(), *(q.begin() + 1)), q.back ()))
q.pop_front(), flag = 1;
if (!flag) break;
} /* for */
return q;
} /* Half_Plane_Inter */

int main()
{
freopen("gallery.in" , "r", stdin );
freopen("gallery.out", "w", stdout);
for (scanf("%d", &T); T--;)
{
scanf("%d", &n);
for (int i = 0; i < n; ++i) scanf("%lf%lf", &p[i].x, &p[i].y);
p[n] = p[0];
for (int i = 0; i < n; ++i) hp[i] = HP(p[i + 1], p[i]);
qsort(hp, n, sizeof hp[0], cmp);
n = std::unique(hp, hp + n, eql) - hp;
const deque <HP> res = Half_Plane_Inter(hp, hp + n);
if (res.size() < 3) printf("0.00\n");
else
{
n = 0;
double ans = 0;
for (deque <HP>::const_iterator iter = res.begin(); iter + 1 != res.end(); ++iter)
p[n++] = cross(*iter, *(iter + 1));
p[n++] = cross(res.front(), res.back());
for (const vec* ths = p + 1; ths + 1 != p + n; ++ths)
ans += fabs((ths[0] - p[0]) * (ths[1] - p[0]));
printf("%.2lf\n", ans /= 2);
} /* else */
} /* for */
return 0;
} /* main */

/*

半平面交模板题,不多说。

*/
poj3525 Most Distant Point from the Sea

/*********************************************************\
* @prob: poj3525 Most Distant Point from the Sea *
* @auth: Wang Junji * @stat: Accepted. *
* @date: June. 26th. 2012 * @memo: 半平面交、二分枚举 *
\*********************************************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <deque>
#include <cmath>

using std::deque;
const int maxN = 110;
const double zero = 1e-10;

struct vec
{
double x, y; vec() {} /* vec */ vec(double x, double y): x(x), y(y) {} /* vec */
vec operator-(const vec& b) const {return vec(x - b.x, y - b.y);} /* operator- */
vec operator+(const vec& b) const {return vec(x + b.x, y + b.y);} /* operator+ */
vec operator*(const double& t) const {return vec(x * t, y * t);} /* operator* */
double operator*(const vec& b) const {return x * b.y - y * b.x;} /* operator* */
double abs() const {return sqrt(x * x + y * y);} /* abs */
} p[maxN];

struct HP
{
vec A, B; double ang, len; HP() {} /* HP */
HP(const vec& A, const vec& B): A(A), B(B)
{
ang = atan2(B.y - A.y, B.x - A.x);
len = (B - A).abs();
} /* HP */
} hp[maxN], hp1[maxN];
int n;

inline int sgn(const double& x)
{return x < -zero ? -1 : x > zero ? 1 : 0;}
/* sgn */

inline double sqr(const double& x) {return x * x;} /* sqr */

inline int cmp(const void* __a, const void* __b)
{
const HP &a = *(HP*)__a, &b = *(HP*)__b;
int tmp = sgn(a.ang - b.ang);
if (tmp) return tmp;
return sgn((b.B - a.A) * (b.A - a.A));
} /* cmp */

inline bool eql(const HP& a, const HP& b)
{return !sgn(a.ang - b.ang);}
/* eql */

inline vec cross(const HP& a, const HP& b)
{
vec AB = a.B - a.A, CD = b.B - b.A,
AC = b.A - a.A, AD = b.B - a.A;
return a.A + AB * ((AC * AD) / (AB * CD));
} /* cross */

inline bool notin(const vec& P, const HP& a)
{return (P - a.B) * (P - a.A) > -zero;}
/* notin */

inline bool Half_Plane_Inter(const HP* fir, const HP* la)
{
static deque <HP> q; q.clear();
for (q.push_back(*fir++), q.push_back(*fir++); fir != la; q.push_back(*fir++))
{
while (q.size() > 1 && notin(cross(*(q.end() - 2), q.back()) , *fir)) q.pop_back ();
while (q.size() > 1 && notin(cross(q.front(), *(q.begin() + 1)), *fir)) q.pop_front();
} /* for */
for (;;)
{
bool flag = 0;
while (q.size() > 2 && notin(cross(*(q.end() - 2), q.back()) , q.front()))
q.pop_back (), flag = 1;
while (q.size() > 2 && notin(cross(q.front(), *(q.begin() + 1)), q.back ()))
q.pop_front(), flag = 1;
if (!flag) break;
} /* for */
return q.size() > 2;
} /* Half_Plane_Inter */

inline bool check(double d)
{
for (int i = 0; i < n; ++i)
{
double x1 = hp[i].A.x, x2 = hp[i].B.x,
y1 = hp[i].A.y, y2 = hp[i].B.y,
len = hp[i].len;
hp1[i].A.x = x1 + (y1 - y2) * d / len;
hp1[i].B.x = x2 + (y1 - y2) * d / len;
hp1[i].A.y = y1 + (x2 - x1) * d / len;
hp1[i].B.y = y2 + (x2 - x1) * d / len;
} /* for */
return Half_Plane_Inter(hp1, hp1 + n);
} /* check */

int main()
{
freopen("sea.in" , "r", stdin );
freopen("sea.out", "w", stdout);
while (~scanf("%d", &n) && n)
{
for (int i = 0; i < n; ++i)
scanf("%lf%lf", &p[i].x, &p[i].y);
p[n] = p[0];
for (int i = 0; i < n; ++i)
hp[i] = HP(p[i], p[i + 1]);
std::qsort(hp, n, sizeof hp[0], cmp);
n = std::unique(hp, hp + n, eql) - hp;
double L = 0, R = 1e4;
while (L - R < -zero)
{
double Mid = (L + R) / 2;
if (check(Mid)) L = Mid;
else R = Mid;
} /* while */
printf("%.10lf\n", R);
} /* while */
return 0;
} /* main */

/*

相当于是求多边形内切圆半径。
只需要二分枚举,然后将所有的边向内移动半径的距离,求对应的半平面是否有相交的区域。

*/
zoj2820 How I Mathematician Wonder What You Are!

/************************************************************\
* @prob: zoj2820 How I Mathematician Wonder What You Are! *
* @auth: Wang Junji * @stat: Accepted. *
* @date: June. 26th. 2012 * @memo: 半平面交、多边形内核 *
\************************************************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <deque>
#include <cmath>

using std::deque;
const int maxN = 50;
const double zero = 1e-8;

struct vec
{
double x, y; vec() {} /* vec */ vec(const vec& b): x(b.x), y(b.y) {} /* vec */
vec(double x, double y): x(x), y(y) {} /* vec */
vec& operator=(const vec& b) {x = b.x, y = b.y; return *this;} /* operator= */
vec operator-(const vec& b) const {return vec(x - b.x, y - b.y);} /* operator- */
vec operator+(const vec& b) const {return vec(x + b.x, y + b.y);} /* operator+ */
vec operator*(const double& d) const {return vec(x * d, y * d);} /* operator+ */
double operator*(const vec& b) const {return x * b.y - y * b.x;} /* operator* */
} p[maxN];

struct HP
{
vec A, B; HP() {} /* HP */ HP(const HP& b): A(b.A), B(b.B) {} /* HP */
HP(const vec& A, const vec& B): A(A), B(B) {} /* HP */
HP& operator=(const HP& b) {A = b.A, B = b.B; return *this;} /* HP */
operator vec() const {return B - A;} /* operator vec */
double operator*(const HP& b) const {return (B - A) * (b.B - b.A);} /* operator* */
double angle() const {return atan2(B.y - A.y, B.x - A.x);} /* angle */
} ele[maxN];
int n;

vec cross(const HP& a, const HP& b)
{
vec AB = vec(a), CD = vec(b),
AC = b.A - a.A, AD = b.B - a.A;
return a.A + AB * ((AC * AD) / (AB * CD));
} /* cross */

inline int sgn(const double& x)
{return x < -zero ? -1 : x > zero ? 1 : 0;}
/* sgn */

inline int cmp(const void* __a, const void* __b)
{
const HP &a = *(HP*)__a, &b = *(HP*)__b;
int tmp = sgn(a.angle() - b.angle());
if (tmp) return tmp;
return sgn((b.B - a.A) * (b.A - a.A));
} /* cmp */

inline bool eql(const HP& a, const HP& b)
{return !sgn(a.angle() - b.angle());}
/* eql */

inline bool notin(const vec& P, const HP& a)
{return (P - a.B) * (P - a.A) > -zero;}
/* notin */

bool Core(HP const* fir, HP const* la)
{
static deque <HP> q; q.clear();
for (q.push_back(*fir++), q.push_back(*fir++); fir != la; q.push_back(*fir++))
{
while (q.size() > 1 && notin(cross(*(q.end() - 2), q.back()), *fir)) q.pop_back();
while (q.size() > 1 && notin(cross(q.front(), *(q.begin() + 1)), *fir)) q.pop_front();
} /* for */
for (;;)
{
bool flag = 0;
while (q.size() > 2 && notin(cross(*(q.end() - 2), q.back()), q.front()))
q.pop_back(), flag = 1;
while (q.size() > 2 && notin(cross(q.front(), *(q.begin() + 1)), q.back()))
q.pop_front(), flag = 1;
if (!flag) break;
} /* for */
return q.size() > 2;
} /* Core */

int main()
{
freopen("Core.in" , "r", stdin );
freopen("Core.out", "w", stdout);
while (~scanf("%d", &n) && n)
{
for (int i = 0; i < n; ++i)
scanf("%lf%lf", &p[i].x, &p[i].y);
p[n] = p[0];
for (int i = 0; i < n; ++i)
ele[i] = HP(p[i], p[i + 1]);
qsort(ele, n, sizeof ele[0], cmp);
n = std::unique(ele, ele + n, eql) - ele;
printf("%d\n", Core(ele, ele + n));
} /* while */
return 0;
} /* main */

/*

半平面交模板题。
参考 http://evalls.yo2.cn/articles/%E5%8D%8A%E5%B9%B3%E9%9D%A2%E4%BA%A4onlogn%E7%9A%84%E7%AE%97%E6%B3%95.html
1) 将所有半平面按极角排序,对于极角相同的,选择性的保留一个。
2) 使用一个双端队列(deque),加入最开始2个半平面。
3) 每次考虑一个新的半平面:
a. while deque顶端的两个半平面的交点在当前半平面外:删除deque顶端的半平面
b. while deque底部的两个半平面的交点在当前半平面外:删除deque底部的半平面
c. 将新半平面加入deque顶端
4) 删除两端多余的半平面。
具体方法是:
a. while deque顶端的两个半平面的交点在底部半平面外:删除deque顶端的半平面
b. while deque底部的两个半平面的交点在顶端半平面外:删除deque底部的半平面
重复a, b直到不能删除为止。
5) 计算出deque顶端和底部的交点即可。

*/