题意:
有一个赛车跑道,可以看做一个加权有向图。每个跑道(有向边)还有一个特点就是,会周期性地打开a秒,然后关闭b秒。只有在赛车进入一直到出来,该跑道一直处于打开状态,赛车才能通过。
开始时所有跑道处于刚打开的状态,求从起点到终点的最短时间。
分析:
设d[i]为起点到节点i的最短时间。
和普通的单源最短路问题一样,只不过在进行松弛操作的时候分两种情况。松弛的前提是,赛道打开的时间不短于赛车通过的时间。
- 赛车从进入直到出跑道,一直是打开状态。则d[v] = min(d[v], d[u] + t)
- 赛道已经关闭或会在中途关闭,则只能等到下次刚刚打开时进入,因此有个等待时间。d[v] = min(d[v], d[u] + wait + t)
1 #include2 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 edges;14 vector 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 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 else58 { //情况二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 }