Description

You have just moved from a quiet Waterloo neighbourhood to a big, noisy city. Instead of getting to ride your bike to school every day, you now get to walk and take the subway. Because you don't want to be late for class, you want to know how long it will take you to get to school. 
You walk at a speed of 10 km/h. The subway travels at 40 km/h. Assume that you are lucky, and whenever you arrive at a subway station, a train is there that you can board immediately. You may get on and off the subway any number of times, and you may switch between different subway lines if you wish. All subway lines go in both directions.

Input

Input consists of the x,y coordinates of your home and your school, followed by specifications of several subway lines. Each subway line consists of the non-negative integer x,y coordinates of each stop on the line, in order. You may assume the subway runs in a straight line between adjacent stops, and the coordinates represent an integral number of metres. Each line has at least two stops. The end of each subway line is followed by the dummy coordinate pair -1,-1. In total there are at most 200 subway stops in the city.

Output

Output is the number of minutes it will take you to get to school, rounded to the nearest minute, taking the fastest route.

Sample Input

0 0 10000 1000
0 200 5000 200 7000 200 -1 -1
2000 600 5000 600 10000 600 -1 -1

Sample Output

21

Source

Waterloo local 2001.09.22

这道题的思路简单来说就是将所有地铁站转换成点,然后预处理所有点间的边权(即将距离转换成时间),然后用最短路算法(例如SPFA)求出起点和目标点的距离。
但是!!!
说的简单,实现起来真TM麻烦。
第一:
需要四舍五入得到答案。
四舍五入的函数不难写,但是在哪里四舍五入是个问题。
回忆了一下做数学题的教训,前面一直用double保存边权,到最后再四舍五入误差最小。

第二:
每点间的距离处理。
你需要判断他们间的路是在地铁里还是人行道,所以我加了一个初始为1的变量p,每次输入-1,-1是就p++。
然后每次在两点间赋权的时候判断是不是在同一条地铁线上。

第三:
现在还没解决的问题,如果两条地铁线交叉,那么赋权就又有问题了,所以我希望可以用坐标来表示点,但是由于坐标可能给的很大,所以一直不知道怎么处理。

 
附上还没完成的代码(甚至样例都是错的),希望可以有所启发(还会不断更新,知道附上AC代码):
 
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
int read()
{
int x=,y=;
char ch=getchar();
while(ch<''||ch>'')
{
if(ch=='-')
y=-;
ch=getchar();
}
while(ch>=''&&ch<='')
{
x=x*+ch-'';
ch=getchar();
}
return x*y;
}
int abs(int x)
{
if(x<)
return -x;
else
return x;
}
int change(double x)
{
int r=(int)x;
if(x-r<0.5)
return r;
else
return r+;
}
double way(int x1,int y1,int x2,int y2)
{
int r1=abs(x1-x2),r2=abs(y1-y2);
return sqrt(r1*r1+r2*r2);
}
struct edge
{
int next,to;
double lon;
} e[];
int map[][],num,node[][],head[],cnt,t[],headd,tail=;
double dist[];
bool vis[];
void add(int from,int to,double lon)
{
e[++cnt].lon=lon;
e[cnt].to=to;
e[cnt].next=head[from];
head[from]=cnt;
}
int main()
{
memset(head,-,sizeof(head));
int x1=read(),y1=read(),x2=read(),y2=read(),x,y,p=,l=change(way(x1,y1,x2,y2)/*);
node[++num][]=x1;
node[num][]=y1;
node[++num][]=x2;
node[num][]=y2;
add(,,l);
add(,,l);
while(scanf("%d%d",&x,&y)!=EOF)
{
if(x==-&&y==-)
{
p++;
continue;
}
node[++num][]=x;
node[num][]=y;
node[num][]=p;
for(int i=; i<num; i++)
{
double dis;
if(node[i][]==p)
dis=way(x,node[i][],y,node[i][])/*;
else
dis=way(x,node[i][],y,node[i][])/*;
// printf("x=%d y=%d node[i][0]=%d node[i][1]=%d dis=%f\n",x,y,node[i][0],node[i][1],dis);
add(num,i,dis),add(i,num,dis);
}
}
for(int i=; i<=num; i++)
dist[i]=2e8;
t[]=;
while(headd!=tail)
{
int r=head[t[headd]];
vis[t[headd]]=;
while(r!=-)
{
if(dist[e[r].to]>dist[t[headd]]+e[r].lon)
{
dist[e[r].to]=dist[t[headd]]+e[r].lon;
printf("e[r].lon=%f e[r].to=%d dist=%f %f\n",e[r].lon,e[r].to,dist[t[headd]],dist[e[r].to]);
if(!vis[e[r].to])
{
vis[e[r].to]=;
t[tail++]=e[r].to;
}
}
r=e[r].next;
}
headd++;
}
printf("%f",dist[]);
return ;
} // FOR C.H

附上最新经谭姐启发写的正解方法代码(思路稍后,仍有问题在调试):

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
// 邻接链保存边
int head[],cnt,num;
struct edge
{
int next,to;
double lon;
} e[];
void add(int from,int to,double lon)
{
e[++cnt].lon=lon;
e[cnt].to=to;
e[cnt].next=head[from];
head[from]=cnt;
}
// 绝对值函数
int abs(int x)
{
if(x<)
return -x;
else
return x;
}
// 求两点间距离的函数
double far(int x1,int y1,int x2,int y2)
{
int r1=abs(x1-x2),r2=abs(y1-y2);
return sqrt(r1*r1+r2*r2);
}
// 将double转变成int的函数
int change(double x)
{
int r=(int)x;
if(x-r<0.5)
return r;
else
return r+;
}
int map[][];
// 输入处理,自认为比以前有所进步
void scan()
{
int x,y,p=,s=;
while(scanf("%d%d",&x,&y)!=EOF)
{
if(x==-&&y==-)
{
// 该条地铁线上的点和前后的点连无向快边
for(int i=; i<=s; i++)
{
double f=far(map[num-s+i-][],map[num-s+i-][],map[num-s+i][],map[num-s+i][])/*;
add(num-s+i-,num-s+i,f);
add(num-s+i,num-s+i-,f);
}
s=;
continue;
}
map[++num][]=x;
map[num][]=y;
s++;
}
}
// 每点到起点的距离
double dist[];
// SPFA的队列
int t[],headd,tail=;
bool vis[];
int main()
{
memset(head,-,sizeof(head));
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
scan();
// 每个点间连一条慢边,虽然可以优化,不用全部连,但是懒得打了,反正最短路嘛
for(int i=; i<=num; i++)
for(int j=; j<=num; j++)
{
double f=far(map[i][],map[i][],map[j][],map[j][])/*;
add(i,j,f);
}
// 每个点和起点连一条慢边
num++;
for(int i=; i<num; i++)
{
double f=far(map[i][],map[i][],x1,y1)/*;
add(i,num,f);
add(num,i,f);
}
// 除起点外和终点连一条慢边
num++;
for(int i=; i<num-; i++)
{
double f=far(map[i][],map[i][],x2,y2)/*;
add(i,num,f);
add(num,i,f);
}
// SPFA求起点到终点的最短路
t[]=num-;
vis[num-]=;
for(int i=; i<=num; i++)
dist[i]=2e8;
dist[num-]=;
while(headd!=tail)
{
int r=head[t[headd]];
printf("r=%d\n",r);
while(r!=-)
{
if(dist[e[r].to]>dist[t[headd]]+e[r].lon)
{
dist[e[r].to]=dist[t[headd]]+e[r].lon;
printf("dist[e[r].to]=%f\n",dist[e[r].to]);
if(!vis[e[r].to])
{
vis[e[r].to]=;
t[tail++]=e[r].to;
}
}
r=e[r].next;
}
headd++;
}
// 输出答案
printf("%d",change(dist[num]));
return ;
} // FOR C.H

终于迎来了最后一次编辑!

之前的程序有一个小错误找了半天,就是SPFA忘记出队,最后终于找到了!

还有,我还是把每个地铁站的点到其他地铁站的距离优化了一下,少加了几条(其实蛮多)边。

最后的AC代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
// 邻接链保存边
int head[],cnt,num;
struct edge
{
int next,to;
double lon;
} e[];
void add(int from,int to,double lon)
{
e[++cnt].lon=lon;
e[cnt].to=to;
e[cnt].next=head[from];
head[from]=cnt;
}
// 绝对值函数
int abs(int x)
{
if(x<)
return -x;
else
return x;
}
// 求两点间距离的函数
double far(int x1,int y1,int x2,int y2)
{
int r1=abs(x1-x2),r2=abs(y1-y2);
return sqrt(r1*r1+r2*r2);
}
// 四舍五入的函数
int change(double x)
{
int r=(int)x;
if(x-r<0.5)
return r;
else
return r+;
}
// 输入处理,自认为比以前有所进步
int map[][];
bool m[][];
void scan()
{
int x,y,p=,s=;
while(scanf("%d%d",&x,&y)!=EOF)
{
if(x==-&&y==-)
{
// 该条地铁线上的点和前后的点连无向快边
for(int i=; i<=s; i++)
{
double f=far(map[num-s+i-][],map[num-s+i-][],map[num-s+i][],map[num-s+i][])/*;
add(num-s+i-,num-s+i,f);
add(num-s+i,num-s+i-,f);
m[num-s+i-][num-s+i]=;
}
s=;
continue;
}
map[++num][]=x;
map[num][]=y;
s++;
}
}
// 每点到起点的距离
double dist[];
// SPFA的队列
int t[],headd,tail=;
bool vis[];
int main()
{
memset(head,-,sizeof(head));
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
scan();
// 每个点间连一条慢边,如果已经连了快边了就不用连
for(int i=; i<=num; i++)
for(int j=; j<=num; j++)
{
if(m[i][j]||m[j][i]||i==j)
continue;
double f=far(map[i][],map[i][],map[j][],map[j][])/*;
add(i,j,f);
}
// 每个点和起点连条慢边
num++;
for(int i=; i<num; i++)
{
double f=far(map[i][],map[i][],x1,y1)/*;
add(i,num,f);
add(num,i,f);
}
// 除起点外和终点连条慢边
num++;
for(int i=; i<num-; i++)
{
double f=far(map[i][],map[i][],x2,y2)/*;
add(i,num,f);
add(num,i,f);
}
// SPFA求起点到终点的最短路
t[]=num-;
vis[num-]=;
for(int i=; i<=num; i++)
dist[i]=2e8;
dist[num-]=;
while(headd!=tail)
{
int r=head[t[headd]];
vis[t[headd]]=;
while(r!=-)
{
if(dist[e[r].to]>dist[t[headd]]+e[r].lon)
{
dist[e[r].to]=dist[t[headd]]+e[r].lon;
if(!vis[e[r].to])
{
vis[e[r].to]=;
t[tail++]=e[r].to;
}
}
r=e[r].next;
}
headd++;
}
// 输出答案
printf("%d",change(dist[num]));
return ;
} // FOR C.H

POJ 2502 Subway-经过预处理的最短路的更多相关文章

  1. POJ 2502 Subway / NBUT 1440 Subway / SCU 2186 Subway(图论,最短距离)

    POJ 2502 Subway / NBUT 1440 Subway / SCU 2186 Subway(图论,最短距离) Description You have just moved from a ...

  2. POJ 2502 - Subway Dijkstra堆优化试水

    做这道题的动机就是想练习一下堆的应用,顺便补一下好久没看的图论算法. Dijkstra算法概述 //从0出发的单源最短路 dis[][] = {INF} ReadMap(dis); for i = 0 ...

  3. POJ 2502 Subway (最短路)

    Subway 题目链接: http://acm.hust.edu.cn/vjudge/contest/122685#problem/L Description You have just moved ...

  4. POJ 2502 Subway ( 最短路 && 最短路建图 )

    题意 : 给出二维平面上的两个点代表起点以及终点,接下来给出若干条地铁线路,除了在地铁线路上行进的速度为 40km/h 其余的点到点间都只能用过步行且其速度为 10km/h ,现问你从起点到终点的最短 ...

  5. POJ 2502 Subway(迪杰斯特拉)

    Subway Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6692   Accepted: 2177 Descriptio ...

  6. POJ 2502 Subway (Dijkstra 最短+建设规划)

    Subway Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6689   Accepted: 2176 Descriptio ...

  7. POJ 2502 Subway

    Subway Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4928   Accepted: 1602 Descriptio ...

  8. (简单) POJ 2502 Subway,Dijkstra。

    Description You have just moved from a quiet Waterloo neighbourhood to a big, noisy city. Instead of ...

  9. Dijkstra+计算几何 POJ 2502 Subway

    题目传送门 题意:列车上行驶40, 其余走路速度10.问从家到学校的最短时间 分析:关键是建图:相邻站点的速度是40,否则都可以走路10的速度.读入数据也很变态. #include <cstdi ...

随机推荐

  1. Javascript版-显示相应图片的详细信息

    Hi All, 分享一个通过JS来显示相应图片的详细信息. 需求:进入页面时,动态加载图片信息:当鼠标移动到某一图片上时,则显示该图片的大图片并显示相应说明信息:当鼠标移开图片时,清除新创建的元素. ...

  2. iOS系统原生 二维码的生成、扫描和读取(高清、彩色)

    由于近期工作中遇到了个需求:需要将一些固定的字段 在多个移动端进行相互传输,所以就想到了 二维码 这个神奇的东东! 现在的大街上.连个摊煎饼的大妈 都有自己的二维码来让大家进行扫码支付.可见现在的二维 ...

  3. ionic 使用mobisscrolls,实现日期选择的插件

    废话不多说,直接说用法: 1,先下载mobisscrolls的破解版,下载地址,链接:http://pan.baidu.com/s/1boSKf51 密码:5dft 当然你也可以去官网下载,不过官网的 ...

  4. Building Particle Filters and Particle MCMC in NIMBLE

    This example shows how to construct and conduct inference on a state space model using particle filt ...

  5. Rxjava observeOn()和subscribeOn()初探

    Rxjava这么强大的类库怎么可能没有多线程切换呢? 其中observeOn()与subscribeOn()就是实现这样的作用的.本文主要讲解observeOn()与subscribeOn()的用法, ...

  6. 再谈PHP错误与异常处理

    博客好久没有更新了,实在惭愧,最近在忙人生大事,哈哈!这段时间没有看什么新的东西,结合项目中遇到的PHP异常处理问题,我又重新梳理了之前模糊的概念,希望对大家理解PHP异常处理有所帮助. 请一定要注意 ...

  7. 【PHP】最详细PHP从入门到精通(三)——PHP中的数组

     PHP从入门到精通 之PHP中的数组 各位开发者朋友大家好,链接上次更新,我们PHP的学习也更深了一层,本次博主给大家带来PHP数组的数组实例详解的相关资料.数组分为数组数值数值,关联数组,多维数组 ...

  8. 【Selenium】Selenium1

    一.Selenium1组件 (1)Selenium服务器,负责启动关闭浏览器:解释和运行从测试程序中传来的Selenium命令:HTTP代理:获取和验证在浏览器和被测试的应用程序之间的传递的HTTP消 ...

  9. idea live template

    最近正在研究如何给idea添加注释模板. 此篇文章是记录在写(开发)注释模板的过程中遇到的坑. 1. methodParameters() 当函数的参数列表为空的时候返回的是: [] 当函数的参数列表 ...

  10. js变量提升和函数提升

    变量,作为编程语言最基础的部分,每种语言的变量不尽相同,但又大径相庭.大部分编程语言的变量有块级作用域,如if.for.while... 但JavaScript不纯在块级作用域,而是函数作用域,并且有 ...