collecting
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
过程:
- 预处理。利用线段判交、线段-多边形位置关系 求出图上任意两点直接相连的距离。(需要特别留意线段在多边形内的情况)
- 二分。直接二分 行李在带上的移动时间 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;
}
相关阅读
1、0-1背包问题 0-1背包问题:有一个贼在偷窃一家商店时,发现有n件物品,第i件物品价值vi元,重wi磅,此处vi与wi都是整数。他希望带走
概述 手写排序算法几乎是程序员面试必问的题目,大多数人都会选择写冒泡排序,如果此时你写的是其他改进过的排序算法,相信会让面试官
数三退一,就是指很多个小朋友围成一个圈,从第一个开始数1.2.3. 第三个小朋友就退出 这个圈,以此类推。第一种方法,以面向过程的方式,此
深入浅出PID控制算法(二)————PID算法离散化和增量式
引言 上篇介绍了连续系统的PID算法,但是计算机控制是一种采样控制,他只能根据采样时刻的偏差来计算控制量,因此计算机控制系统中
def gethint(secret, guess): secret_dict = {} # 创建字典 用于存储公牛和母牛的数量(AB) guess_dict = {} A =