poj 2502

题目概述

城市地图是一个二维坐标系,你要从家里到学校,行走速度10km/h,城市中有地铁线路,地铁只在行驶在某些点之间,两点之间的行驶路线都是直线,地铁速度40km/h,给定家,学校,地铁站点的位置以及地铁线路,问最快多久到学校
每次到地铁站时都会立刻坐上地铁,并且可以在线路上的任何站点下车
地图坐标的单位是米

时限

1000ms/3000ms

输入

第一行两对整数,分别描述家和学校的位置,其后若干行,每行若干对整数,描述一条地铁线上相邻站点的位置,每行以-1 -1结束,输入到EOF结束,数据只有一组

限制

城市中最多200个地铁站

输出

一个数,到学校最少需要的分钟数,四舍五入到整数

样例输入

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

样例输出

21

讨论

图论,单源最短路,bellman_ford队列优化算法,首先一眼能看出是单元最短路,但是这个题麻烦在构图,走路可以在任何两点间穿梭,而地铁只能在相邻两点之间跑,需要注意,可能会出现V形地铁线,使得两点之间坐地铁比走路还慢,因而地铁线上非相邻两点间也要算行走用时
实现层面上,首先注意,题目给的速度是km/h,而地图单位是m,而且最后输出的是min,这中间牵扯的简单换算都不能忽略,构图时,这显然是得用邻接矩阵,先构造每条地铁线相邻两点之间的用时,之后构造行走部分的用时,遇到有地铁两点需要在行走和地铁之间取较小值,不能直接取地铁的用时,最后一遍最短路,返回结果即可

题解状态

532K,16MS,C++,1546B

题解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 204
#define memset0(a) memset(a,0,sizeof(a))

int x[MAXN], y[MAXN];//地图上点的坐标
double graph[MAXN][MAXN], dist[MAXN];//邻接矩阵 最短路长度
queue<int>q;//辅助队列
bool inq[MAXN];//辅助数组 在队列中
double dis(int x1, int y1, int x2, int y2)//两点间距离 这回要用好几次 就没删
{
    return sqrt(double(x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));//传的参数是int 需要强转一下 否则sqrt是c++11的int型 poj不认
}
double fun()
{
    scanf("%d%d%d%d", &x[0], &y[0], &x[1], &y[1]);//intput//家和学校分别是0点和1点
    int index = 2;
    while (~scanf("%d%d", &x[index], &y[index])) {//input//这部分是读取地铁线的情况以及处理
        index++;
        while (scanf("%d%d", &x[index], &y[index]) && (x[index] != -1 || y[index] != -1)) {
            graph[index - 1][index] = graph[index][index - 1] = dis(x[index], y[index], x[index - 1], y[index - 1]) / 40000;//由于单位换算 40*1000
            index++;
        }
    }
    for (int p = 0; p < index; p++) {//下面处理行走部分的用时 这种写法完全可以整合成一个for
        for (int i = 0; i < p; i++) {
            graph[p][i] = graph[i][p];
        }
        for (int i = p + 1; i < index; i++) {
            if (!graph[p][i])
                graph[p][i] = dis(x[p], y[p], x[i], y[i]) / 10000;
            else
                graph[p][i] = min(graph[p][i], dis(x[p], y[p], x[i], y[i]));
        }
    }
    for (int p = 1; p < index; p++)//下面是bellman_ford算法
        dist[p] = INF;
    q.push(0);
    inq[0] = 1;
    while (!q.empty()) {
        int a = q.front();
        q.pop();
        inq[a] = 0;
        for (int p = 0; p < index; p++) {
            if (a != p&&dist[p] > dist[a] + graph[a][p]) {
                dist[p] = dist[a] + graph[a][p];
                if (!inq[p]) {
                    q.push(p);
                    inq[p] = 1;
                }
            }
        }
    }
    return dist[1] * 60;//从小时换算到分钟
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    printf("%.0lf\n", fun());//output
}

EOF

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值