题意:
有一个赛车跑道,可以看做一个加权有向图。每个跑道(有向边)还有一个特点就是,会周期性地打开a秒,然后关闭b秒。只有在赛车进入一直到出来,该跑道一直处于打开状态,赛车才能通过。
开始时所有跑道处于刚打开的状态,求从起点到终点的最短时间。
分析:
设d[i]为起点到节点i的最短时间。
和普通的单源最短路问题一样,只不过在进行松弛操作的时候分两种情况。松弛的前提是,赛道打开的时间不短于赛车通过的时间。
- 赛车从进入直到出跑道,一直是打开状态。则d[v] = min(d[v], d[u] + t)
- 赛道已经关闭或会在中途关闭,则只能等到下次刚刚打开时进入,因此有个等待时间。d[v] = min(d[v], d[u] + wait + t)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 300 + 10; 5 const int INF = 1000000000; 6 7 struct Edge 8 { 9 int from, to, a, b, t; 10 Edge(int u, int v, int a, int b, int t):from(u), to(v), a(a), b(b), t(t) {} 11 }; 12 13 vector<Edge> edges; 14 vector<int> G[maxn]; 15 bool inq[maxn]; 16 int n, m, s, t, d[maxn]; 17 18 void Init() 19 { 20 edges.clear(); 21 for(int i = 0; i < n; ++i) G[i].clear(); 22 } 23 24 void AddEdge(int u, int v, int a, int b, int t) 25 { 26 edges.push_back(Edge(u, v, a, b, t)); 27 int m = edges.size(); 28 G[u].push_back(m-1); 29 } 30 31 void SPFA() 32 { 33 memset(inq, false, sizeof(inq)); 34 for(int i = 0; i < n; ++i) d[i] = INF; 35 queue<int> Q; 36 d[s] = 0; inq[s] = true; Q.push(s); 37 38 while(!Q.empty()) 39 { 40 int u = Q.front(); Q.pop(); 41 inq[u] = false; 42 for(int i = 0; i < G[u].size(); ++i) 43 { 44 Edge& e = edges[G[u][i]]; 45 int v = e.to, a = e.a, b = e.b, t = e.t; 46 if(a < t) continue; 47 int now = d[u] % (a+b); 48 if(now + t <= a) 49 {//情况一 50 if(d[v] > d[u] + t) 51 { 52 d[v] = d[u] + t; 53 Q.push(v); 54 inq[v] = true; 55 } 56 } 57 else 58 {//情况二 59 int wait = a + b - now; 60 if(d[v] > d[u] + wait + t) 61 { 62 d[v] = d[u] + wait + t; 63 Q.push(v); 64 inq[v] = true; 65 } 66 } 67 } 68 } 69 } 70 71 int main() 72 { 73 //freopen("in.txt", "r", stdin); 74 75 int kase = 0; 76 while(scanf("%d%d%d%d", &n, &m, &s, &t) == 4) 77 { 78 s--; t--; 79 Init(); 80 for(int i = 0; i < m; ++i) 81 { 82 int u, v, a, b, t; 83 scanf("%d%d%d%d%d", &u, &v, &a, &b, &t); 84 AddEdge(u-1, v-1, a, b, t); 85 } 86 SPFA(); 87 printf("Case %d: %d\n", ++kase, d[t]); 88 } 89 90 return 0; 91 }
代码君
时间: 2024-12-28 06:12:37