Aizu 2346 Runaway Domino(警察抓小偷)

题意:给一条不自交的折线,折线最多有1000个点,有两个小偷在折线上一点,分别往相反方向走,速度相同为v1,有一个警察在(x, y),速度为v2,方向自选,如果警察碰到小偷,则小偷立马停下,如果小偷走到各自的终点,则小偷立马停下,现在问,警察需要最少多少时间使得两个小偷都停下。(v1 < v2)

链接:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2346

解法:先考虑制止一个小偷,二分时间(很明显满足二分性吧),然后,求出在该时间 t 内,这个小偷走到的点(O(N)求),然后判断点是否在(警察所在的点为圆心,v2 * t为半径)的圆内,如果在,说明时间可能会更少,如果不在,说明时间需要更多。。因为保证了v1 < v2,这样做一定是对的。。

两个小偷怎么办,只能想到的办法就是,先抓一个,再抓另一个,先抓哪个都枚举一下,如果你在制止这个小偷之前,他已经到达终点了,那么一开始就没有必要去抓他,同时,当你抓到一个后,再去抓另一个,起点以抓到第一个所在的点为起点,,两边都枚举一下,就可以了。。

这题又有精度问题,取1e-6才能过

具体为什么这样贪心是对的,不清楚,但不这么做,就无法做了吧。。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

const double eps = 1e-6;
int sgn(double x){
    if(abs(x) < eps) return 0;
    else return x > 0 ? 1 : - 1;
}
struct Point{
    double x, y;
    Point(){};
    Point(double x1, double y1){
        x = x1, y = y1;
    }
};
typedef Point Vector;

int n;
Point p[1024], s1, s2, news2, news1;
int v1, v2;
Point readp(){
    int x, y;
    scanf("%d%d",&x,&y);
    return Point(x, y);
}

Vector operator + (Vector a, Vector b){
    return Vector(a.x + b.x, a.y + b.y);
}
Vector operator - (Vector a, Vector b){
    return Vector(a.x - b.x, a.y - b.y);
}
double operator % (Vector a, Vector b){
    return a.x * b.y - a.y * b.x;
}
double operator * (Vector a, Vector b){
    return a.x * b.x + a.y * b.y;
}
Vector operator / (Vector a, double b){
    return Vector(a.x / b, a.y / b);
}
Vector operator * (Vector a, double b){
    return Vector(a.x * b, a.y * b);
}
bool operator == (Point a, Point b){
    return sgn(a.x - b.x) == 0 && sgn(a.y - b.y) == 0;
}
bool PoiOnSeg(Point p, Point p1, Point p2){
    if(sgn((p - p1) % (p - p2)) != 0) return false;
    if(sgn((p1 - p) * (p2 - p)) > 0) return false;
    else return true;
}
double Length(Vector v){
    return sqrt(v.x * v.x + v.y * v.y);
}
double Len2(Vector v){
    return v.x * v.x + v.y * v.y;
}
Vector Unitv(Vector v){
    return v / Length(v);
}

int findf(Point s1){
    int f = n + 10;
    for(int i = 0; i + 1 < n; i++){
        if(PoiOnSeg(s1, p[i], p[i + 1]))
        {
            f = min(f, i);
        }
    }
    return f;
}

double ans;
void maxtime(Point s1, double &maxt1, double &maxt2){
    maxt1 = 0;
    Point nowp = s1;
    int f = findf(s1);
    for(int i = f + 1; i < n; i++){
        maxt1 += Length(nowp - p[i]);
        nowp = p[i];
    }
    nowp = s1;
    maxt2 = 0;
    for(int i = f; i >= 0; i--){
        maxt2 += Length(nowp - p[i]);
        nowp = p[i];
    }

    maxt1 /= v1;
    maxt2 /= v1;
}

Point getto(Point s1, double t, int dir){
    double nowt = 0;
    Point nowp = s1;
    int f = findf(nowp);
    if(dir == 1)
    {
        for(int i = f + 1; i < n; i++){
            if(nowp == p[i]) continue;
            double needt = Length(nowp - p[i]) / v1;
            if(sgn(nowt + needt - t) >= 0){
                nowp = nowp + Unitv(p[i] - nowp) * (t - nowt) * v1;
                break;
            }
            else{
                nowt += needt;
                nowp = p[i];
            }
        }
    }
    else
    {
        for(int i = f; i >= 0; i--){
            if(nowp == p[i]) continue;
            double needt = Length(nowp - p[i]) / v1;
            if(sgn(nowt + needt - t) >= 0){
                nowp = nowp + Unitv((p[i] - nowp)) * (t - nowt) * v1;
                break;
            }
            else{
                nowt += needt;
                nowp = p[i];
            }
        }
    }
    return nowp;
}

bool PoiInCir(Point p, Point c, double r){
    return sgn(Len2(p - c) - r * r) <= 0;
}

double solve(Point sta, Point aim, double maxt, int dir){
    double l = 0.0, r = maxt, mid;
    int tt = 100;
    while(r - l > 1e-10 && tt--){
        mid = (l + r) * 0.5;
        Point p1 = getto(aim, mid, dir);
        if(PoiInCir(p1, sta, mid * v2)) r = mid;
        else l = mid;
    }
    return l;
}

double solve1(){
    double maxt1, maxt2, t1, t2;

    maxtime(s1, maxt1, maxt2);
    t1 = solve(s2, s1, maxt1, 1);
    if(sgn(t1 - maxt1) == 0) return 1e20;
    news2 = getto(s1, t1, 1);
    news1 = getto(s1, t1, 2);

    if(sgn(t1 - maxt2) >= 0) return t1;

    maxtime(news1, maxt1, maxt2);

    t2 = solve(news2, news1, maxt2, 2);

    return t1 + t2;
}

double solve2(){
    double maxt1, maxt2, t1, t2;

    maxtime(s1, maxt1, maxt2);
    t2 = solve(s2, s1, maxt2, 2);
    if(sgn(t2 - maxt2) == 0) return 1e20;
    news2 = getto(s1, t2, 2);
    news1 = getto(s1, t2, 1);

    if(sgn(t2 - maxt1) >= 0) return t2;

    maxtime(news1, maxt1, maxt2);

    t1 = solve(news2, news1, maxt1, 1);

    return t1 + t2;
}

int main(){
    scanf("%d",&n);
    for(int i = 0; i < n; i++){
        p[i] = readp();
    }
    s1 = readp(); scanf("%d",&v1);
    s2 = readp(); scanf("%d",&v2);

    double maxt1, maxt2;
    maxtime(s1, maxt1, maxt2);

    double ans = min(solve1(), solve2());
    ans = min(ans, max(maxt1, maxt2));
    printf("%.10f\n", ans);
    return 0;
}

你可能感兴趣的:(几何)