题意:
在一个赛车比赛中,有n 个交叉点和m 个单向道路,每条道路周期性的开启a秒,关闭b秒,通过时间是t秒, 求从S到T 的最短时间?
思路:
和正常的迪杰斯特拉一样,存的是时间,优先时间小的先弹出。
只不过在压入队列中 分情况讨论:
1.如果现在的时间能进入这条道路,并且能在道路关闭之前出来,就进入队列。
2.否则就等这条道路在开启时 在进入队列。
吐槽:
会有重边的存在,写成vector 存边就过去了= =
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#define Siz(x) (int)x.size()
using namespace std;
int n,m ,s,t,ks;
const int oo = 5e7+10;
struct Node{
int c,d;
bool operator < (const Node& rhs) const {
return d > rhs.d;
}
Node(int c=0,int d=0):c(c),d(d){}
};
struct Edge{
int u,v,a,b,t;
void read(){
scanf("%d %d %d %d %d",&u, &v, &a, &b, &t);
}
}p;
priority_queue<Node>q;
vector <Edge>edges;
int dp[307];
vector<int>g[307];
bool vis[307];
void dij(){
for (int i = 0; i <= n; ++i){
vis[i] = 0;
dp[i] = oo;
}
dp[s] = 0;
while(!q.empty()) q.pop();
q.push(Node(s,0));
while(!q.empty()){
Node u = q.top(); q.pop();
int c = u.c;
if (vis[c])continue;
vis[c] = 1;
for (int i = 0; i < Siz(g[c]); ++i){
int v = g[c][i];
Edge& e = edges[v];
v = e.v;
int a = e.a,b = e.b, t = e.t;
int dd = dp[c] % (a+b);
if (t > a) continue;
if (dd + t > a){
if (dp[v] > dp[c] + a+b-dd+t){
dp[v] = dp[c]+a+b+t-dd;
q.push(Node(v,dp[v]));
}
}
else {
if (dp[v] > dp[c] + t){
dp[v] = dp[c] + t;
q.push(Node(v,dp[v]));
}
}
}
}
}
int main(){
while(~scanf("%d %d %d %d",&n ,&m, &s, &t)){
for (int i = 0; i <= n; ++i)g[i].clear();
edges.clear();
for (int i = 0; i < m; ++i){
p.read();
int u = p.u, v = p.v;
edges.push_back(p);
g[u].push_back(i);
}
dij();
printf("Case %d: %d\n",++ks,dp[t]);
}
return 0;
}
/**
3 2 1 3
1 2 5 6 3
2 3 7 7 6
3 2 1 3
1 2 5 6 3
2 3 9 5 6
Case 1: 20
Case 2: 9
**/