題意:
有一個賽車跑道,可以看做一個加權有向圖。每個跑道(有向邊)還有一個特點就是,會週期性地打開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 ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
#define MAXN 1000000
#define INT_MAX 0x3ffffff
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;
}