【BZOJ 1020】 [SHOI2008]安全的航线flight

【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1020

【题意】

【题解】

二分+判断点是否在多边形区域内+计算点到直线的最短距离
对于每条线段,假设这条线段为(x,y)首先将线段的两段尝试更新距离陆地距离最近的距离中最远的距离ans,并求出其在陆地上对应的点u和v;(如果x和y都在陆地上那么u、v就都是陆地上的点)
然后在这条(x,y)中找一个点mid
使得pv=pu;
然后先用p点尝试更新一下答案ans(找离p点最近的陆地上的点)
然后如果pv< ans,那么这条直线就不用再找了;
因为如果是(x,y)上异于p的点;
它里陆地的距离只会比pv更近.
(画图就知道了);
这其实就只是用中点去剪枝而已.
但效果很好.
如果不满足pv< ans
则把xp和py两条直线再进行处理就好;
写个循环队列咯。

【完整代码】

#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%lld",&x)
#define red(x) scanf("%lf",&x)

typedef pair<int, int> pii;
typedef pair<LL, LL> pll;

const int dx[9] = { 0,1,-1,0,0,-1,-1,1,1 };
const int dy[9] = { 0,0,0,-1,1,-1,1,-1,1 };
const double pi = acos(-1.0);
const int N = 40;
const int M = 100e4 + 10;
const double eps = 1e-4;

struct point
{
    double x, y;
};

point operator -(point u, point v) {
    point t; t.x = u.x - v.x; t.y = u.y - v.y; return t;
}

struct abc
{
    point p1, p2;
};
double crs(point u, point v) { return u.x*v.y - u.y*v.x; }
bool upon(point u, point v, point w) {
    return !crs(v - u, w - u) && (u.x - v.x)*(u.x - w.x) <= 0 && (u.y - v.y)*(u.y - w.y) <= 0;
}
bool havitr(point u, point v, point s, point t) {
    return crs(v - u, s - u)*crs(v - u, t - u) <= 0 && crs(t - s, u - s)*crs(t - s, v - s) <= 0;
}
struct disp { point p; double dis; };
double dot(point u, point v) { return u.x*v.x + u.y*v.y; }
double dist(point u, point v) { return sqrt(dot(u - v, u - v)); }
disp lss(disp u, disp v) { return (u.dis<v.dis) ? u : v; }

point getitr(point u, point s, point v, point t) {
    double tmp = crs(t, u - v) / crs(s, t);
    u.x += s.x*tmp; u.y += s.y*tmp; return u;
}

point s;

struct land
{
    int tot;
    point p[N];
    void init()
    {
        rei(tot);
        rep1(i, 1, tot)
            red(p[i].x), red(p[i].y);
        p[tot + 1] = p[1];
    }
    bool inside(point t)
    {
        int i, sum = 0;
        for (i = 1; i <= tot; i++)
            if (upon(t, p[i], p[i + 1])) return 1;
        t.y += 0.1;
        s.y = t.y; s.x = -10001;
        for (i = 1; i <= tot; i++)
            if (havitr(s, t, p[i], p[i + 1])) sum++;
        t.y -= 0.1;
        return sum & 1;
    }
};

int c, n;
double ans = 0;
point a[N];
abc q[M];
land b[N];

disp nearst(point u, point v, point w) {
    disp t;
    if (v.x == w.x && v.y == w.y) t.p = v; else
        if (dot(u - v, w - v) <= 0) t.p = v; else
            if (dot(u - w, v - w) <= 0) t.p = w; else {
                point s = v - w; swap(s.x, s.y); s.x = -s.x;
                t.p = getitr(u, s, v, w - v);
            }
    t.dis = dist(t.p, u); return t;
}

point updata(point t)
{
    rep1(i, 1, c)
        if (b[i].inside(t))
            return t;
    disp temp;
    temp.dis = 1e20;
    rep1(i, 1, c)
        rep1(j, 1, b[i].tot)
        temp = lss(temp, nearst(t, b[i].p[j], b[i].p[j + 1]));
    ans = max(ans, temp.dis);
    return temp.p;
}

int main()
{
    //freopen("F:\\rush.txt", "r", stdin);
    rei(c), rei(n);
    rep1(i, 1, n)
    {
        red(a[i].x), red(a[i].y);
    }
    rep1(i, 1, c)
        b[i].init();
    int head = 0, tail = 0;
    rep1(i, 1, n - 1)
    {
        q[++tail].p1 = a[i], q[tail].p2 = a[i + 1];
        updata(a[i]);
    }
    while (head != tail)
    {
        head = head%M + 1;
        point x = q[head].p1, y = q[head].p2;
        point u = updata(x), v = updata(y),mid;
        while (dist(x, y) > eps)
        {
            mid.x = (x.x + y.x) / 2, mid.y = (x.y + y.y) / 2;
            if (dist(u, mid) < dist(v, mid))
                x = mid;
            else
                y = mid;
        }
        double temp = dist(u, x); updata(x);
        if (temp > ans+eps)
        {
            tail = tail%M + 1, q[tail].p1 = q[head].p1, q[tail].p2 = mid;
            tail = tail%M + 1, q[tail].p1 = mid, q[tail].p2 = q[head].p2;
        }
    }
    printf("%.2f\n", ans);
    return 0;
}
posted @ 2017-10-04 18:45  AWCXV  阅读(190)  评论(0编辑  收藏  举报