//除了边的权值之外每个点还附带一个权值,所以在松弛操作的时候要把点的权值也计算进去
//另外在总费用最小的情况下要输出字典序最小的路径,同样是在松弛操作那里处理
//如果能更新d[i]使d[i]变小则直接更新
//另外在总费用最小的情况下要输出字典序最小的路径,同样是在松弛操作那里处理
//如果能更新d[i]使d[i]变小则直接更新
//如果是与d[i]相同则判断一下如果更新的话会不会使路径的字典序更小,如果能才更新否则不更新;这一点和记录花费那很像
#include <iostream>
#include <memory.h>
#include <stdio.h>
using namespace std;
#define Max_V 1005
const int IN = (1<<28);
int G[105][105];
int Path[105][105];
int Tax[105];
int N,S,D;
void Floyd()
{
for( int u = 1; u <= N; u++ )
for( int v = 1; v <= N; v++ )
for( int w = 1; w <= N; w++ )
{
if( G[v][w] > G[v][u] + G[u][w] + Tax[u] )
{
G[v][w] = G[v][u] + G[u][w]+ Tax[u];
Path[v][w] = Path[v][u];
}
else if( G[v][w] == G[v][u] + G[u][w] + Tax[u] )
{
if( Path[v][w] > Path[v][u] )
{
Path[v][w] = Path[v][u];
}
}
}
}
void Print(int i, int j)
{
if( i==j )
{
printf("%d",i);
return;
}
printf("%d-->",i);
Print(Path[i][j],j);
}
int main()
{
while( cin >> N, N!=0)
{
memset(G, 0, sizeof(G));
memset(Path, 0, sizeof(Path));
for( int i = 1; i <= N; i++ )
{
for( int j = 1; j <= N; j++ )
{
Path[i][j] = j;
cin >> G[i][j];
if( G[i][j] == -1 )
{
G[i][j] = IN;
}
}
}
for( int i = 1; i <= N; i++ )
cin >> Tax[i];
Floyd();
while( cin >> S >> D, S != -1 || D != -1 )
{
if( S==D )
{
printf("From %d to %d :\n",S,D);
printf("Path: %d\n",S);
printf("Total cost : %d\n\n", 0);
continue;
}
printf("From %d to %d :\n",S,D);
printf("Path: ");
Print(S,D);
printf("\n");
printf("Total cost : %d\n\n", G[S][D]);
}
}
return 0;
}