​题目传送门​

UVA—Funny Car Racing Dijkstra + 堆优化_ios

题意:

有一个赛车跑道,可以看做一个加权有向图。每个跑道(有向边)还有一个特点就是,会周期性地打开a秒,然后关闭b秒。只有在赛车进入一直到出来,该跑道一直处于打开状态,赛车才能通过。

开始时所有跑道处于刚打开的状态,求从起点到终点的最短时间。

分析:

和普通的单源最短路类似,在更新边的权值的时候,更改下条件即可。

首先需要判断时间time,time = dis[pos] % ( 开启时间 + 关闭时间 ) (去除完整周期)。那么很容易得到 : 当 time > open 的时候为关闭状态。

对于关闭状态:
权值为:剩余关闭时间 + val

对于开启状态:
1、如果剩余开启时间足够通过,权值为:val(注意存在恰好通过)
2、剩余时间不足以通过,权值为:剩余总共时间 + val

AC代码:

#include <iostream>
#include <vector>
#include <utility>
#include <cstring>
#include <algorithm>
#include <map>
#include <queue>
#include <stack>
#include <cstdio>
#include <set>
#define
using namespace std;
typedef long long ll;


#define
#define
typedef pair<int, int> P;
struct Edge
{
int first;
int open;
int close;
int second;
bool operator < (const Edge& t)const {
return t.second < this->second;
}
};

vector<Edge>vec[MAXN];
priority_queue<Edge, vector<Edge> >que;
ll dis[MAXN];
bool vis[MAXN];
ll N, M, START, END;

void Dijkstra(int start) {

dis[start] = 0;
que.push({ start,0,0,0 });
while (!que.empty()) {
Edge tmp = que.top();
que.pop();
if (vis[tmp.first] == true) {
continue;
}
vis[tmp.first] = true;
for (int i = 0; i < vec[tmp.first].size(); i++) {
ll pos = vec[tmp.first][i].first;
ll val = vec[tmp.first][i].second;
ll open = vec[tmp.first][i].open;
ll close = vec[tmp.first][i].close;
ll time = dis[tmp.first] % (open + close);
if (time >= open) {
dis[pos] = min(dis[tmp.first] + (close - (time - open)) + val, dis[pos]);
if (!vis[pos])
que.push({ pos,open,close,dis[pos] });
}
else {
if (open - time >= val) {
dis[pos] = min(dis[tmp.first] + val, dis[pos]);
if (!vis[pos])
que.push({ pos,open,close,dis[pos] });
}
else {
dis[pos] = min(dis[tmp.first] + val + (open + close) - time, dis[pos]);
if (!vis[pos])
que.push({ pos,open,close,dis[pos] });
}

}
}
}
}

int main() {
ios;
ll T = 0;
while (cin>> N >> M >> START >> END) {
fill(dis, dis + N + 1, INT_MAX);
memset(vis, false, sizeof(vis));
for (vector<Edge>& t : vec) {
t.clear();
}
for (int i = 0; i < M; i++) {
ll a, b, c, d, e;
cin >> a >> b >> c >> d >> e;
if (c < e)
continue;
vec[a].push_back({ b,c,d,e });
}
Dijkstra(START);
cout << "Case " << ++T << ": ";
cout << dis[::END] << endl;

}




return 0;
}