ch_g

ECUST_ACMer —— ch_g
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

[POJ][1271][Nice Milk][半平面交]

Posted on 2011-02-28 14:06  ch_g  阅读(379)  评论(0编辑  收藏  举报
/*
题目:Nice Milk
题目来源:POJ 1271
题目难度:中等偏难
题目内容或思路:
半平面交(黑书习题)
一开始一直TLE,以为是算法可以更优,结果是细节问题。
做题日期:2011.2.28
*/
#include
<cstdio>
#include
<cstdlib>
#include
<climits>
#include
<iostream>
#include
<algorithm>
#include
<cstring>
#include
<string>
#include
<queue>
#include
<map>
#include
<vector>
#include
<bitset>
#include
<cmath>
#include
<set>
using namespace std;

const double eps = 1e-8;
const int N = 22;

struct cpoint {
double x, y;
cpoint(
double x = 0, double y = 0) : x(x), y(y) {}
};

int dcmp(double x){
if (x < -eps) return -1; else return x > eps;
}

double sqr(double x) {return x * x;}

double dis(cpoint a, cpoint b) {
return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
}

double cross(cpoint p0, cpoint p1, cpoint p2) {
return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}

struct cvector {
cpoint s, e;
double ang, d;
};

void setline(double x1, double y1, double x2, double y2, cvector &v) {
v.s.x
= x1; v.s.y = y1;
v.e.x
= x2; v.e.y = y2;
v.ang
= atan2(y2 - y1, x2 - x1);
if (dcmp(x1 - x2))
v.d
= (x1 * y2 - x2 * y1) / fabs(x1 - x2);
else
v.d
= (x1 * y2 - x2 * y1) / fabs(y1 - y2);
}

bool parallel(const cvector &a, const cvector &b) {
double u = (a.e.x - a.s.x) * (b.e.y - b.s.y)
- (a.e.y - a.s.y) * (b.e.x - b.s.x);
return dcmp(u) == 0;
}

cpoint crosspoint(
const cvector &a, const cvector &b) {
cpoint res;
double u = cross(a.s, a.e, b.s), v = cross(a.e, a.s, b.e);
res.x
= (b.s.x * v + b.e.x * u) / (u + v);
res.y
= (b.s.y * v + b.e.y * u) / (u + v);
return res;
}

bool veccmp(const cvector &l, const cvector &r) {
if (dcmp(l.ang - r.ang)) return l.ang < r.ang;
return l.d < r.d;
}

cvector deq[N];

void HalfPanelCross(cvector vec[], int n, cpoint cp[], int &m) {
int i, tn; m = 0;
sort(vec, vec
+ n, veccmp);
for (i = tn = 1; i < n; ++i)
if (dcmp(vec[i].ang - vec[i - 1].ang))
vec[tn
++] = vec[i];
n
= tn;
int bot = 0, top = 1;
deq[
0] = vec[0];
deq[
1] = vec[1];
for (i = 2; i < n; ++i) {
if (parallel(deq[top], deq[top - 1]) ||
parallel(deq[bot], deq[bot
+ 1]) )return;
while (bot < top && dcmp( cross(vec[i].s, vec[i].e,
crosspoint(deq[top], deq[top
- 1])) ) < 0 )
top
--;
while (bot < top && dcmp( cross(vec[i].s, vec[i].e,
crosspoint(deq[bot], deq[bot
+ 1])) ) < 0 )
bot
++;
deq[
++top] = vec[i];
}
while (bot < top && dcmp(cross(deq[bot].s, deq[bot].e,
crosspoint(deq[top], deq[top
- 1])) ) < 0 )
top
--;
while (bot < top && dcmp(cross(deq[top].s, deq[top].e,
crosspoint(deq[bot], deq[bot
+ 1])) ) < 0 )
bot
++;
if (top <= bot + 1) return ;
for (i = bot; i < top; ++i)
cp[m
++] = crosspoint(deq[i], deq[i + 1]);
if (bot < top + 1)
cp[m
++] = crosspoint(deq[bot], deq[top]);
for (i = 0; i < m; ++i) {
if (dcmp(cp[i].x) == 0) cp[i].x = 0;
if (dcmp(cp[i].y) == 0) cp[i].y = 0;
}
}

double PolygonArea(cpoint p[], int n) {
if (n < 3) return 0;
double s = p[0].y * (p[n - 1].x - p[1].x);
for (int i = 1; i < n; ++i)
s
+= p[i].y * (p[i - 1].x - p[(i + 1) % n].x);
return fabs(s / 2);
}

int n, k, h;
cpoint cp[N], tp[N];
cvector v[N], v1[N], v2[N];
int stat[130000], tot;

int cnt(int x) {
int res = 0;
while (x) {
if (x & 1) res++;
x
>>= 1;
}
return res;
}

void dfs(int st, int pos, int cnt) {
if (cnt == k) {
stat[tot
++] = st;
return;
}
if (cnt > k || pos == n || n - pos < k - cnt) return;
dfs(st, pos
+ 1, cnt);
dfs(st
+ (1 << pos), pos + 1, cnt + 1);
}

void solve() {
int m;
for (int i = 0; i < n; ++i) {
scanf(
"%lf%lf", &cp[i].x, &cp[i].y);
}
k
= min(k, n);
if (k == 0 || h == 0) {
puts(
"0.00");
return ;
}
tot
= 0;
dfs(
0, 0, 0);
double res = 1e200;
for (int i = 0; i < n; ++i) { // 一开始setline都是在下面的循环里面进行的,导致一直TLE
setline(cp[i].x, cp[i].y, cp[(i + 1) % n].x, cp[(i + 1) % n].y, v1[i]);
double d = dis(cp[i], cp[(i + 1) % n]);
double dx = h / d * ( cp[i].y - cp[(i + 1) % n].y);
double dy = h / d * (-cp[i].x + cp[(i + 1) % n].x);
setline(cp[i].x
+ dx, cp[i].y + dy, cp[(i + 1) % n].x + dx,
cp[(i
+ 1) % n].y + dy, v2[i]);
}
for (int i = 0; i < tot; ++i) {
int st = stat[i];
for (int j = 0; j < n; ++j) {
if (st & (1 << j))
v[j]
= v2[j];// 一开始setline都是在这里进行的,导致一直TLE
else
v[j]
= v1[j];// 现在改成了先算好每条边,存在v1[],v2[]中
}
HalfPanelCross(v, n, tp, m);
res
= min(res, PolygonArea(tp, m));
}
printf(
"%.2lf\n", PolygonArea(cp, n) - res);
}

int main() {
#ifndef ONLINE_JUDGE
freopen(
"D:\\in.txt", "r", stdin);
#endif
while (scanf("%d%d%d", &n, &k, &h), n + k + h) {
solve();
}
return 0;
}