import java.io.*;
import java.util.*;
/**
* pass
* 弗洛伊德 应用
* 从删除最后一个开始
* @author XA_GDD
*
*/
public class CodeForces295B {
static long dis[][];//第i行中的第j个数的值
static int delete[];//要删除的节点
static long result[];//删除第i个节点之前,剩余顶点对之间最短路径的长度之和
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
dis = new long[n+5][n+5];
result = new long[n+5];
delete = new int[n+5];
for(int i = 1;i <= n;i++) {
Arrays.fill(dis[i], 0);
}
Arrays.fill(result, Integer.MAX_VALUE);
Arrays.fill(delete, 0);
for(int i = 1;i <= n;i++) {
st = new StringTokenizer(br.readLine());
for(int j = 1;j <= n;j++) {
dis[i][j] = Integer.parseInt(st.nextToken());
}
}
st = new StringTokenizer(br.readLine());
for(int i = 1;i <= n;i++) {//要删除的节点
delete[i] = Integer.parseInt(st.nextToken());
}
int index = 1;
//从要删除最后一个到第一个进行松弛操作
for(int k = n ;k >= 1;k--) {
for(int i = 1;i <= n;i ++) {
for(int j = 1;j <= n;j++) {
if(dis[i][delete[k]] + dis[delete[k]][j] < dis[i][j]) {
dis[i][j] = dis[i][delete[k]] + dis[delete[k]][j];
}
}
}
long tmp = 0;
//删除第k个节点之前,剩余节点之间最短路径的长度之和
for(int i = n;i >= k;i--) {
for(int j = n;j >= k;j--) {
tmp += dis[delete[i]][delete[j]];
}
}
result[index] = tmp;
index ++;
}
for(int i = n;i >= 1;i--) {
System.out.print(result[i] + " ");
}
}
}