#include <iostream>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
int edges[101][101];
long long d[101][101][101];
int nnext[101][101];
#define INF 987654321
int main(void)
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
edges[i][j] = INF;
if (i == j)
{
edges[i][j] = 0;
}
nnext[i][j] = -1;
}
}
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
if (edges[a][b] != 0)
{
if (edges[a][b] > c)
{
edges[a][b] = c;
nnext[a][b] = b;
}
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
d[0][i][j] = edges[i][j];
}
}
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (i == j)
continue;
d[k][i][j] = d[k - 1][i][j];
if (d[k][i][j] > d[k - 1][i][k] + d[k - 1][k][j])
{
d[k][i][j] = d[k - 1][i][k] + d[k - 1][k][j];
nnext[i][j] = nnext[i][k];
}
}
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (d[n][i][j] == INF)
d[n][i][j] = 0;
cout << d[n][i][j] << " ";
}
cout << "\n";
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (d[n][i][j] == 0)
{
cout << "0";
}
else
{
int x = i;
int size = 1;
while (x != j)
{
//cout << x << " ";
size++;
x = nnext[x][j];
}
cout << size << " ";
x = i;
while (x != j)
{
cout << x << " ";
size++;
x = nnext[x][j];
}
cout << j;
}
cout << "\n";
}
}
return 0;
}
전형적인 플로이드 알고리즘에 경로를 추가한 알고리즘이다. 다익스트라와 같이 플로이드 알고리즘은 간선의 next 를 정보를 저장하면 없는 간선을 next 로 가르키기 때문에 next 배열을 새로 만들어야 한다.