先用Floyd算法求得从任意两个连通点的最短路(有向),然后横向求得从第 i 个人出发传播的给所有人的时间(题目上说以最后一个人接收到信息为准,在这里卡了好久,搞不懂为什么要取max)记为singleTime,然后再纵向比对,看起点是哪个人rumor传播得更快(取min)记最终答案为 res,开始传播的那个人为 resi。
还有一句,在Floyd算法中,d [ k, i, j ] 代表的是经过前 k 个点(不一定遍历所有前 k 个点),从 i 号点传播到 j 号点的最短路。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 110
#define INF 0x3f3f3f3f
using namespace std;
int n;
int d[N][N];
void floyd() // 基于动态规划,将三维d[k, i, j]降为二维,三维形式如下面的注释
{
for (int k = 1; k <= n; k ++)
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
// 三维形式:d[k, i, j] = min(d[k - 1, i, j], d[k - 1, i, k] + d[k - 1, k, j]) 都用的是上一层的结果,可以优化
int main()
{
while(scanf("%d", &n), n)
{
memset(d, 0x3f, sizeof d);
for (int i = 1; i <= n; i ++)
{
int k;
scanf("%d", &k);
while(k --)
{
int a, b;
scanf("%d%d", &a, &b);
d[i][a] = b; // 题目说明了不会输入重边
}
}
floyd();
int res = INF, resi = 0;
for (int i = 1; i <= n; i ++)
{
int singleTime = 0;
for (int j = 1; j <= n; j ++)
{
if(i == j) continue;
singleTime = max(singleTime, d[i][j]);
}
if(res > singleTime)
{
res = singleTime;
resi = i;
}
}
if(res == INF) puts("disjoint");
else printf("%d %d\n", resi, res);
}
return 0;
}