有N个关键的多米诺骨牌,这些牌通过一些路径相连接,这些路径是由一排其他骨牌构成的。已知每一条路径上的骨牌倒下需要的时间。现在从把编号为1的关键骨牌推倒,问多长时间后所有的骨牌(包括关键牌和它们之间的路径上的骨牌)都倒下,时间精确到小数点后一位。
骨牌可以往两个方向倒,因此路径都是双向的。可以把N个关键牌抽象为N个点,路径抽象为点之间的边。然后通过求单源最短路径的算法求出从第一个关键牌到其他关键牌所需的最短时间。要求的是所有牌倒下的时间,而关键牌可以看成路径的起点或终点,因此可以枚举每一条边,根据边的两个端点的最短路径以及边长,确定一下当前边的所有牌倒下的时间是多少。取这些边中倒下的时间最长的那一个作为答案,同时记录最后一张倒下的牌是端点还是中间的牌,如果是端点,则记录它是第几个关键牌,如果不是端点,则记录这条边的起始关键牌和结束关键牌的序号。如果只有一个关键点,那么倒下的时间是0。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 501;
const int E = 250001;
const int MAX = 0xfffffff;
struct Edge
{
int pnt;
int dis;
int next;
}edge[E];
int cur;
int neigh[N];
int n, e;
int mindis[N];
int que[N], front, rear;
bool inque[N];
double ans;
int ansbeg, ansend;
void init()
{
cur = 0;
for (int i = 0; i < n; ++i) neigh[i] = -1;
}
void addedge(int beg, int end, int dis)
{
edge[cur].pnt = end;
edge[cur].dis = dis;
edge[cur].next = neigh[beg];
neigh[beg] = cur;
++cur;
}
void spfa(int s)
{
for (int i = 0; i < n; ++i)
{
mindis[i] = MAX;
inque[i] = false;
}
front = rear = 0;
mindis[s] = 0;
inque[s] = true;
que[rear++] = s;
while (front != rear)
{
int pre = que[front];
inque[pre] = false;
int te = neigh[pre];
while (te != -1)
{
int pnt = edge[te].pnt;
if (mindis[pre] + edge[te].dis < mindis[pnt])
{
mindis[pnt] = mindis[pre] + edge[te].dis;
if (!inque[pnt])
{
inque[pnt] = true;
que[rear++] = pnt;
if (rear == N) rear = 0;
}
}
te = edge[te].next;
}
if (++front == N) front = 0;
}
}
void updateans(double tans, int tbeg, int tend)
{
if (tans > ans)
{
ans = tans;
ansbeg = tbeg;
ansend = tend;
}
}
void getans()
{
double t;
int te, pnt;
ans = -MAX;
for (int i = 0; i < n; ++i)
{
te = neigh[i];
while (te != -1)
{
pnt = edge[te].pnt;
if (mindis[i] + edge[te].dis == mindis[pnt])
{
t = (mindis[i] + mindis[pnt] + edge[te].dis) / 2.0;
updateans(t, pnt, pnt);
}
else if (mindis[i] + edge[te].dis > mindis[pnt])
{
t = (mindis[i] + mindis[pnt] + edge[te].dis) / 2.0;
updateans(t, i, pnt);
}
te = edge[te].next;
}
}
if (ans == -MAX)
{
ans = 0;
ansbeg = ansend = 0;
}
if (ansbeg > ansend) swap(ansbeg, ansend);
}
int main()
{
int beg, end, dis, T = 1;
while (scanf("%d%d", &n, &e) != EOF)
{
if (n == 0 && e == 0) break;
init();
for (int i = 0; i < e; ++i)
{
scanf("%d%d%d", &beg, &end, &dis);
--beg;
--end;
addedge(beg, end, dis);
addedge(end, beg, dis);
}
spfa(0);
getans();
printf("System #%d\n", T++);
if (ansbeg == ansend)
{
printf("The last domino falls after %.1lf seconds, at key domino %d.\n", ans, ansbeg + 1);
}
else
{
printf("The last domino falls after %.1lf seconds, between key dominoes %d and %d.\n", ans, ansbeg + 1, ansend + 1);
}
printf("\n");
}
return 0;
}