Collecting Luggage - UVALive 2397 - 蓝桥杯 算法训练

vjudge 题目链接

vj速度第一哈哈

玄学优化 = 。=

二分,最短路,计算几何

问题描述

  航班结束后,提取行李的过程并不琐碎。手提箱和行李箱出现在一条传送带上,数百名乘客争夺有利的位置从中找到并取回自己的所有物。近日,成田机场管理局已决定使这一过程更加高效。在重新设计行李认领区前,他们需要一个模拟程序,使得乘客认领行李时的耗时更平均。这个模拟假定乘客们走一条由直线段组成的路径并使用最少的时间走到他们的行李处。
  对于这个问题,传送带被描述为一个简单多边形。在传送带的某些点上出现一件行李,然后以恒定的速度沿着传送带移动。乘客一开始在一个传送带组成的多边形外的点。在行李出现的同时,乘客以恒定的速度(大于行李移动的速度)移动去提取行李。乘客的路径可以接触但不能穿过传送带,且能让乘客在最短的时间内和行李位于同一个点。
  在接下来这幅图中,传送带被描述成多边形ABCDEF。行李开始在左上角(A点)并按时针方向沿多边形边缘移动,如小箭头所示。乘客一开始在P点,并开始按最短的时间能和行李到达同一点(图中M点)的路径移动。乘客的移动路径如红色箭头所示。该图对应第一个输入样例。

输入格式

  输入包含一个或多个测试点来描述领取行李的场景。一个场景描述开头一行为一个单独的整数N(3<=N<=100),多边形的顶点数。接下来N行每行两个整数xi,yi,(|xi|,|yi|<=10000),按逆时针顺序给出多边形顶点的坐标。多边形是简单多边形,也就是说它不自交,不重合。多边形的描述后接下来一行两个整数px,py(|px|,|py|<=10000),乘客起始位置所在点的坐标。接下来两个正整数VL,VP(0<VL<VP<=10000),分别是行李和乘客的速度。所有坐标的单位是米,速度的单位是米/分钟。
  你可以假设乘客位于多边形外。行李将会从多变形的第一个顶点开始按逆时针顺序沿传送带移动。
  输入以一行一个单独的0结束。

输出格式

  对于每组数据,输出一行,包括测试数据编号(从1开始编号)和乘客取得行李的最少时间。使用格式如样例输出所示(用冒号隔开分钟和秒),四舍五入到最近的整数。秒数占两位(不足用前导0补齐)。

样例输入

6
0 40
0 0
20 0
20 20
40 20
40 40
120 40
70 100
4
0 0
10 0
10 10
0 10
100 100
10 11
0

样例输出

Case 1: Time = 1:02
Case 2: Time = 12:36

数据规模和约定

  对于10%的数据,给出的多边形保证是凸多边形
  对于20%的数据,3<=n<=4
  对于40%的数据,3<=n<=50
  对于100%的数据,3<=n<=100,数组组数<=10,坐标绝对值、速度<=10000


 

 

过程:

  1. 预处理。利用线段判交线段-多边形位置关系 求出图上任意两点直接相连的距离。(需要特别留意线段在多边形内的情况)
  2. 二分。直接二分 行李在带上的移动时间 T1 。求出在行李移动 T1 后的位置 P ,然后用最短路求出乘客到位置 P 的最短时间 T2 ,判断 T1 T2 大小关系,继续二分。
#include <bits/stdc++.h>
using namespace std;
#define Rep(x,f,t) for(int x=(f);x<=(t);++x)
#define For(x,f,t) for(int x=(f);x<(t);++x)
#define DFor(x,f,t) for(int x=(f);x>(t);--x)
#define SD(x) scanf("%d",&(x))
#define SDD(x,y) scanf("%d%d",&(x), &(y))
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define CLRSTL(x) while(!(x).empty()) (x).pop();
#define p(x) cout<<x
#define pl(x) cout<<x<<endl
#define Pause freopen("CON","r",stdin);system("pause");
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<double,double> pdd;
void Debug(){}
const int INF=0x3f3f3f3f;
const double eps=1e-8;
const int MAXN=205, MAXM=MAXN*MAXN;
stringstream outs;

inline int sgn(double x) { if(fabs(x)<eps) return 0; if(x<0) return -1; else return 1;}

struct Point {
    double x, y;
    int id;
    Point(double xx=0.0, double yy=0.0): x(xx), y(yy) { id=-1; };
    Point operator +(const Point &b)const {
        return Point(x + b.x,y + b.y);
    }
    Point operator -(const Point &b)const {
        return Point(x - b.x,y - b.y);
    }
    Point operator *(const double &b)const {
        return Point(x * b,y * b);
    }
    Point operator /(const double &b)const {
        return Point(x / b,y / b);
    }
    double operator ^(const Point &b)const { //叉积 det
        return x*b.y - y*b.x;
    }
    double operator *(const Point &b)const { //点积 dot
        return x*b.x + y*b.y;
    }
    void read() { scanf("%lf%lf", &x, &y); }
    void show() { printf("(%f,%f)\n", x, y); }
};

struct Line {
    Point s, e;
    Line() {};
    Line(Point _s, Point _e) { s=_s, e=_e; };
    static inline double dist(Point a,Point b) { return sqrt((a-b)*(a-b)); }
    static inline bool inter(Line l1,Line l2) {
        return inter(l1.s,l1.e,l2.s,l2.e);
    }
    static inline bool inter(Point xa, Point xb, Point ya, Point yb) {
        return
        max(xa.x,xb.x) > min(ya.x,yb.x) &&
        max(ya.x,yb.x) > min(xa.x,xb.x) &&
        max(xa.y,xb.y) > min(ya.y,yb.y) &&
        max(ya.y,yb.y) > min(xa.y,xb.y) &&
        sgn((ya-xb)^(xa-xb))*sgn((yb-xb)^(xa-xb)) < 0 &&
        sgn((xa-yb)^(ya-yb))*sgn((xb-yb)^(ya-yb)) < 0;
    }
};

class Passager {
public:
    Point pos;
    int vp;
    void readPoint() { pos.read(); }
    void readSpeed() { SD(vp); }
};

class Conveyer {
public:
    Point *vertex;
    int pcnt, vc;
    double totTime, totDist;
    Conveyer(int n): pcnt(n) { vertex=new Point[n+5]; }
    void readPoint() { For(i, 0, pcnt) vertex[i].read(), vertex[i].id=i; }
    void readSpeed() { SD(vc); }
    inline bool OnSeg(Point P,Line L) {
        return
        sgn((L.s-P)^(L.e-P)) == 0 &&
        sgn((P.x - L.s.x) * (P.x - L.e.x)) <= 0 &&
        sgn((P.y - L.s.y) * (P.y - L.e.y)) <= 0;
    }
    int pointInPloy(Point p) { //1:内, 0:边, -1:外
        Point *poly=vertex;
        int n=pcnt, cnt=0;
        Line ray,side;
        ray.s = p, ray.e.y = p.y, ray.e.x = -100000000000.0;
        for(int i = 0;i < n;i++) {
            side.s = poly[i], side.e = poly[(i+1)%n];
            if(OnSeg(p,side))
                return 0;
            if(sgn(side.s.y - side.e.y) == 0)
                continue;
            if(OnSeg(side.s,ray)) {
                if(sgn(side.s.y - side.e.y) > 0)
                    cnt++;
            }
            else if(OnSeg(side.e,ray)) {
                if(sgn(side.e.y - side.s.y) > 0)
                    cnt++;
            }
            else if(Line::inter(ray,side))
                cnt++;
        }
        if(cnt % 2 == 1)
            return 1;
        else
            return -1;
    }
    static inline bool cmp(const Point &a, const Point &b) {
        if( sgn(a.x-b.x)==0 ) return sgn(a.y-b.y)<=0;
        else return sgn(a.x-b.x)<=0;
    }
    bool lineInPloy(Point m, Point n) {
        vector<Point> vec;
        Point s, mid, e;
        Line MN(m, n);
        For(i, 0, pcnt) {
            if(OnSeg(vertex[i], MN)) vec.push_back(vertex[i]);
        }
        if(m.id==-1) vec.push_back(m);
        if(n.id==-1) vec.push_back(n);
        sort(vec.begin(), vec.end(), cmp);
        bool tag=false;
        DFor(i, vec.size()-1, 0) {
            s=vec[i];
            e=vec[i-1];
            mid.x=(s.x+e.x)/2;
            mid.y=(s.y+e.y)/2;
            if(pointInPloy(mid)==1) {
                tag=true;
                break;
            }
        }
        return tag;
    }
    bool judge(Point s, Point e) {
        Rep(k, 1, pcnt) {
            if( Line::inter(s,e, vertex[k%pcnt],vertex[k-1]) ) return false;
        }
        return !lineInPloy(s, e);
    }
};

struct Qnode {
    int u;
    double dis;
    Qnode(int u, double dis): u(u), dis(dis) {}
    bool operator < (const Qnode &r) const {
        return sgn(dis-r.dis)>0;
    }
};

Conveyer *belt;
Passager *pax;
//pretreat
double bDist[MAXN];
double drtG[MAXN][MAXN];
//dijkstra
bool vis[MAXN];
double lowc[MAXN];
priority_queue<Qnode> pq;

void read(int n) {
    belt=new Conveyer(n), pax=new Passager();
    belt->readPoint(), pax->readPoint();
    belt->readSpeed(), pax->readSpeed();
    belt->vertex[pax->pos.id=n] = pax->pos;
}

void pretreat() {
    int n=belt->pcnt;
    Point *v=belt->vertex;
    bDist[0]=0.0;
    For(i,0,n) {
        if(i) bDist[i]=bDist[i-1] + Line::dist(belt->vertex[i-1], belt->vertex[i]);
    }
    belt->totDist=bDist[n-1] + Line::dist(belt->vertex[n-1], belt->vertex[0]);
    belt->totTime=belt->totDist / belt->vc;
    Rep(i, 0, n) { //邻接矩阵
        drtG[i][i]=0;
        Rep(j, i+1, n) {
            if(belt->judge(v[i], v[j]))
                drtG[i][j]=drtG[j][i]=Line::dist(v[i], v[j]);
            else
                drtG[i][j]=drtG[j][i]=INF;
        }
    }
}

void Dijkstra(int beg) {
    int n=belt->pcnt, nn=n+1;
    Rep(i, 0, n+1) vis[i]=false, lowc[i]=INF;
    CLRSTL(pq);
    pq.push(Qnode(beg, lowc[beg]=0.0));
    while(!pq.empty()) {
        Qnode cur=pq.top(); pq.pop();
        int u=cur.u;
        double dis=cur.dis;
        if(vis[u]) continue;
        vis[u]=true;
        Rep(v, 0, nn) {
            if(!vis[v] && sgn(dis+drtG[u][v] - lowc[v])<0)
                pq.push(Qnode(v, lowc[v]=dis+drtG[u][v]));
        }
    }
}

Point findP(double t) {
    double dis=t*belt->vc;
    dis=fmod(dis, belt->totDist);
    int low=lower_bound(bDist, bDist+belt->pcnt, dis) - bDist - 1;
    dis=dis-bDist[low];
    Point *v=belt->vertex;
    Point e=(v[(low+1)%belt->pcnt]-v[low])/drtG[low+1][low]; //单位向量
    return v[low] + e*dis;
}

int chk(double t) {
    Point *v=belt->vertex;
    int n=belt->pcnt;
    v[n+1]=findP(t);
    Rep(i, 0, n) {
        drtG[i][n+1]=drtG[n+1][i] = (belt->judge(v[i], v[n+1])? Line::dist(v[i], v[n+1]): INF);
    }
    Dijkstra(n);
    //return sgn(lowc[n+1]/pax->vp - t)<=0; //T人 <= T行李
    return sgn(lowc[n+1]/pax->vp - t); //T人 <= T行李
}

int BSearch() {
    double lf, rt, mid;
    int n=belt->pcnt;
    Point *v=belt->vertex;
    double dis=INF;
    For(i, 0, n) dis=min(dis, drtG[i][n]);
    lf=0;
    rt=belt->totDist + dis/pax->vp;
    while(rt-lf > eps) {
        mid=(rt+lf)/2;
        switch(chk(mid)) { //switch效率高于if-else
        case -1:
            rt=mid;
            break;
        case 0:
            rt=lf;
            break;
        case 1:
            lf=mid;
            break;
        }
    }
    return lf*60+0.5+eps;
}

void solve() {
    static int cas=1;
    int ans=BSearch();
    printf("Case %d: Time = %d:%02d\n", cas++, ans/60, ans%60);
    free(belt), free(pax);
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
#endif

    int n;
    while(~SD(n) && n) {
        read(n);
        pretreat();
        solve();
    }
    return 0;
}

 

 

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值