题意分析:
从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; }