[UVA 10801]Lift Hopping[Dijkstra][建图]

题目链接: [UVA 10801]Lift Hopping[Dijkstra][建图]

题意分析:

从0层开始,一共有n台电梯供你到达目的地k层。每台电梯往上走一层都要消耗t[i]的时间,并且电梯只能在特定的楼层停下,换乘电梯要花费60s的时间,而且呢,你不能用楼梯上楼,只能搭电梯。。。。(hentai!)问:最快到达楼层k的时间是多少?不能到达就输出-1。

解题思路:

这题技巧就是体现在建图上,图建好了,用dijkstra跑一遍就行了。

具体建图就是用mp[i][j]代表从楼层i到楼层j的最小距离。这里不考虑换乘,先这样把图建好。

对于换乘,我们在dijkstra更新节点的时候使用。具体为:d[y] = min(d[y], d[x] + mp[x][y] + 60);

这里更新时加上60s的具体理由在于:这里我们默认第一次进电梯算是换乘,所以加上60s。这样不管是一路搭到底(每个d[i]都加60,一起比较起来没有影响),还是有换乘(本来就该加60s嘛)。都不会影响。

这样在计算最终结果时,减去60就是最终的结果了(因为默认了第一次进入电梯算换乘)。

个人感受:

感觉好神奇的建图~

具体代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<sstream>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f, MAXN = 111;
int t[MAXN], mp[MAXN][MAXN], floors[MAXN], len, vis[MAXN], d[MAXN], n, k;
string s;

void build(int node)
{
    for (int i = 0; i < len; ++i)
        for (int j = i + 1; j < len; ++j)
        {
            int &a = floors[j], &b = floors[i];
            int dis = (a - b) * t[node];
            if (dis < mp[b][a])
                mp[a][b] = mp[b][a] = dis;
        }
}

void dijkstra()
{
    memset(vis, 0, sizeof vis);
    memset(d, 0x3f, sizeof d);
    d[0] = 0;
    for (int i = 0; i < 100; ++i)
    {
        int x, mx = INF;
        for (int y = 0; y < 100; ++y) if(!vis[y] && d[y] <= mx) mx = d[x = y];
        vis[x] = 1;
        for (int y = 0; y < 100; ++y) d[y] = min(d[y], d[x] + mp[x][y] + 60);
    }
    if (d[k] == INF)
        cout << "IMPOSSIBLE\n";
    else
        cout << max(0, d[k] - 60) << '\n';//小心目标楼层为0的情况
}

int main()
{
    while(~scanf("%d%d", &n, &k))
    {
        memset(mp, 0x3f, sizeof mp);
        for (int i = 0; i < n; ++i)
            scanf("%d", &t[i]);
        getchar();
        for (int i = 0; i < n; ++i)
        {
            len = 0;
            int x;
            getline(cin, s);
            stringstream ss(s);
            while (ss >> x)
            {
                floors[len++] = x;
            }
            build(i);
        }
        dijkstra();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值