SGU_103
与一般的最短路问题不同的是,我们要首先判断什么时候才可以走上某条路,因此我们需要计算从当前这刻起两个灯变成相同颜色的最近的那一时刻,当然也有可能两灯根本不会变成相同的颜色,总体的一个思想就是如果两灯的一个最小公周期内没有出现相同的颜色,那么后面也一定不会出现相同的颜色。
在计算等待时间的时候,可以依次枚举也可以一次性加到两灯有其一变化的最近的那一刻。在计算最短路的过程中,也可以适当用一些剪枝以减少计算量,比如如果d[u]+t[i]>=d[v],即就算现在立刻可以上路也不能更新d[v],那么自然就不用计算两个灯在什么候会变成相同颜色了,同时如果枚举过程中当前时刻已经超过了d[v]-t[i],那么也可以终止枚举了。
#include<stdio.h>
#include<string.h>
#define MAXD 310
#define MAXM 30000
#define INF 0x5f5f5f5f5f5f5f5fll
int N, M, S, T, e, first[MAXD], next[MAXM], v[MAXM], w[MAXM], icol[MAXD], it[MAXD], t[MAXD][2];
int q[MAXD], inq[MAXD], p[MAXD];
long long int d[MAXD];
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
void add(int a, int b, int c)
{
w[e] = c;
v[e] = b;
next[e] = first[a];
first[a] = e;
e ++;
}
void init()
{
int i, j, k, a, b, c;
char st[5];
scanf("%d%d", &N, &M);
for(i = 1; i <= N; i ++)
{
scanf("%s%d%d%d", st, &a, &b, &c);
it[i] = a;
if(st[0] == 'B')
{
icol[i] = 0;
t[i][0] = c, t[i][1] = b;
}
else
{
icol[i] = 1;
t[i][0] = b, t[i][1] = c;
}
}
memset(first, -1, sizeof(first));
e = 0;
for(i = 0; i < M; i ++)
{
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
add(b, a, c);
}
}
long long int nextt(int a, int b, long long int now, long long int limit)
{
int sta, stb;
long long int i, k;
k = gcd(t[a][0] + t[a][1], t[b][0] + t[b][1]);
k = (t[a][0] + t[a][1]) / k * (t[b][0] + t[b][1]);
if(now + k < limit)
limit = now + k;
for(i = now; i < limit; i ++)
{
if(i < it[a])
sta = icol[a];
else
{
k = (i - it[a]) % (t[a][0] + t[a][1]);
if(k < t[a][0])
sta = (icol[a] ^ 1);
else
sta = icol[a];
}
if(i < it[b])
stb = icol[b];
else
{
k = (i - it[b]) % (t[b][0] + t[b][1]);
if(k < t[b][0])
stb = (icol[b] ^ 1);
else
stb = icol[b];
}
if(sta == stb)
return i;
}
return -1;
}
void printpath(int cur)
{
if(cur == S)
printf("%d", S);
else
{
printpath(p[cur]);
printf(" %d", cur);
}
}
void solve()
{
int i, j, front, rear, u;
long long int k;
memset(d, 0x5f, sizeof(d));
d[S] = 0;
memset(inq, 0, sizeof(inq));
front = rear = 0;
q[rear ++] = S;
while(front != rear)
{
u = q[front ++];
if(front > N)
front = 0;
inq[u] = 0;
for(i = first[u]; i != -1; i = next[i])
if(d[u] + w[i] < d[v[i]])
{
k = nextt(u, v[i], d[u], d[v[i]] - w[i]);
if(k != -1)
{
d[v[i]] = k + w[i];
p[v[i]] = u;
if(!inq[v[i]])
{
q[rear ++] = v[i];
if(rear > N)
rear = 0;
inq[v[i]] = 1;
}
}
}
}
if(d[T] == INF)
printf("0\n");
else
{
printf("%lld\n", d[T]);
printpath(T);
printf("\n");
}
}
int main()
{
while(scanf("%d%d", &S, &T) == 2)
{
init();
solve();
}
return 0;
}