一、原题地址
二、大致题意
给一座旅馆在XY坐标轴上的情况,每个点代表一个房间。人上楼有走楼梯和走电梯两种方法,电梯有相对的运行速度。读入电梯和楼梯所在的位置。询问给出的两点间的最快走法。
三、思路
如果两点在同一层,显然是直接走过去最快。
两点在不同层时,首先上楼和下楼是必须的。此时只需要找到人到达楼梯口(电梯口)+楼梯口(电梯口)到达终点的最小值即可。
由于楼梯(电梯)数可能很多,所以用二分确定最接近起始点位置的楼梯(电梯)。
四、代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,cl,ce,v,q;
int lou[100005];
int dian[100005];
int work(int sx,int sy,int ex,int ey)
{
if(sx==ex)
return abs(sy-ey);
int k=lower_bound(lou,lou+cl,sy)-lou;
int ans=inf;
if(k<cl)
{
int pos=lou[k];
ans=min(abs(sy-pos)+abs(ey-pos)+abs(sx-ex),ans);
}
if(k>0)
{
int pos=lou[k-1];
ans=min(abs(sy-pos)+abs(ey-pos)+abs(sx-ex),ans);
}
k=lower_bound(dian,dian+ce,sy)-dian;
if(k<ce)
{
int pos=dian[k];
ans=min(abs(sy-pos)+abs(ey-pos)+abs(sx-ex)/v+(((abs(sx-ex)%v)==0)?0:1),ans);
}
if(k>0)
{
int pos=dian[k-1];
ans=min(abs(sy-pos)+abs(ey-pos)+abs(sx-ex)/v+(((abs(sx-ex)%v)==0)?0:1),ans);
}
return ans;
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&cl,&ce,&v);
for(int i=0;i<cl;i++)
scanf("%d",&lou[i]);
for(int i=0;i<ce;i++)
scanf("%d",&dian[i]);
sort(lou,lou+cl);
sort(dian,dian+ce);
scanf("%d",&q);
while(q--)
{
int sx,sy,ex,ey;
scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
printf("%d\n",work(sx,sy,ex,ey));
}
getchar();
getchar();
}
五、反思
二分写了很久一直WA。网上浏览大佬代码发现lower_bound和upper_bound的使用。
upper_bound(i) 返回的是键值为i的元素可以插入的最后一个位置(上界)。
lowe_bound(i) 返回的是键值为i的元素可以插入的位置的第一个位置(下界)。
在这道题里这两者没有影响。因为当起始点和y坐标与楼梯(电梯)的y坐标重叠时,必然是选择直接上楼(下楼)更快。