SGU103 Traffic Lights
题目大意
给出一张无向图,每个顶点有一盏红绿灯,按照一定的周期变换(左闭右开)
对于某一时刻,若一条边两个端点的颜色相同,则视为可通过,所需时间为边的权值
问0时刻从s出发,最快何时可以到达t
算法思路
不难发现,到达某个点的时间越早越好,可以使用最短路算法求解
对于松弛操作,先找出从dis[u]开始第一次颜色相等的时刻,加上边权后更新dis[v]
不难发现,等待时间最多是一个半周期,否则不存在,粗略的证明如下:
- 若v的周期与u的周期等长,则结果可在一个周期内判定
- 否则不妨设v周期短于u,考虑u的第一个周期,假设先绿灯后红灯
- 若u为绿灯时v出现绿灯,则一个周期内存在相等的时刻
- 否则u为绿灯时v必定是红灯,而u为红灯时由于周期不等长,v必定出现红灯
- 此时u的第一个周期还未结束,故一个半周期内必定存在相等的时刻
时间复杂度: SPFA - O(kE∗200)
代码
/**
* Copyright (c) 2015 Authors. All rights reserved.
*
* FileName: 103.cpp
* Author: Beiyu Li <sysulby@gmail.com>
* Date: 2015-05-21
*/
#include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)
typedef long long LL;
typedef pair<int, int> Pii;
const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;
const int maxn = 300 + 5;
const int maxe = 28000 + 5;
int psz;
struct Edge {
int v, w;
Edge *next;
} epl[maxe], *e[maxn];
void add_edge(int u, int v, int w)
{
Edge *i = epl + psz++;
i->v = v; i->w = w; i->next = e[u]; e[u] = i;
}
int n, m, s, t;
bool c[maxn];
int r[maxn], l[maxn][3];
int dis[maxn], pre[maxn];
bool inq[maxn];
int color(int u, int now)
{
now = (now - r[u] + l[u][2]) % l[u][2];
return now < l[u][c[u]^1]? c[u] ^ 1: c[u];
}
int calc(int u, int v, int now)
{
For(i,now,now+300) if (color(u, i) == color(v, i)) return i;
return inf;
}
void spfa()
{
deque<int> deq;
memset(dis, 0x3f, sizeof(dis));
memset(inq, false, sizeof(inq));
dis[s] = 0; inq[s] = true; deq.push_back(s);
while (!deq.empty()) {
int u = deq.front(); deq.pop_front(); inq[u] = false;
for (Edge *i = e[u]; i; i = i->next) {
int v = i->v, w = calc(u, v, dis[u]) + i->w;
if (dis[v] <= w) continue;
dis[v] = w; pre[v] = u;
if (inq[v]) continue; inq[v] = true;
deq.empty() || dis[v] < dis[deq.front()]?
deq.push_front(v): deq.push_back(v);
}
}
}
void print(int u)
{
if (u == s) { printf("%d", u + 1); return; }
print(pre[u]); printf(" %d", u + 1);
}
int main()
{
scanf("%d%d", &s, &t);
--s; --t;
scanf("%d%d", &n, &m);
rep(i,n) {
char buf[8];
scanf("%s%d%d%d", buf, &r[i], &l[i][0], &l[i][1]);
c[i] = (buf[0] == 'P');
l[i][2] = l[i][0] + l[i][1];
}
while (m--) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
--u; --v;
add_edge(u, v, w);
add_edge(v, u, w);
}
spfa();
if (dis[t] == inf) puts("0");
else printf("%d\n", dis[t]), print(t), puts("");
return 0;
}