题意:
现在有一副完全图, 将他转化成线图。
线图就是 把原来的图上的边都变成点, 然后如果原来的任意2条边存在公共点, 他们就会有一条边, 边权为原来的2条边的和。
最后求出线图中的任意2点的最短路的和。
题解:
对于原图来说
现在有 ( a, b) -> (c, d) 他的花费是 W(a,b) + W(c, d) + 2*min( d[a][c], d[a][d], d[b][c], d[b][d] ) 的值。其中d[i][j] 代表 从i走到j的最小花费。
现在我们枚举起点(i, j) 然后对于其他点都找到 min(d[a][i], d[a][j])
然后把这个值sort一遍, 每个位置的贡献就是他后面的数目的个数。
代码:

1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define fi first 7 #define se second 8 #define pb push_back 9 #define lson l,m,rt<<1 10 #define rson m+1,r,rt<<1|1 11 #define lch tr[x].son[0] 12 #define rch tr[x].son[1] 13 #define max3(a,b,c) max(a,max(b,c)) 14 #define min3(a,b,c) min(a,min(b,c)) 15 typedef pair<int,int> pll; 16 const int inf = 0x3f3f3f3f; 17 const LL INF = 0x3f3f3f3f3f3f3f3f; 18 const LL mod = 998244353; 19 const int N = 505; 20 int d[N][N]; 21 int dd[N*N]; 22 int main(){ 23 int T, n; 24 scanf("%d", &T); 25 while(T--){ 26 scanf("%d", &n); 27 LL ans = 0; 28 for(int i = 1; i <= n; i++) 29 for(int j = 1; j <= n; j++){ 30 scanf("%d", &d[i][j]); 31 if(i < j) 32 ans = (ans+d[i][j])%mod; 33 } 34 int t = n*(n-1)/2 - 1; 35 ans = ans * t % mod; 36 for(int k = 1; k <= n; k++) 37 for(int i = 1; i <= n; i++) 38 for(int j = 1; j <= n; j++) 39 d[i][j] = min(d[i][j], d[i][k]+ d[k][j]); 40 for(int i = 1; i <= n; i++){ 41 for(int j = i+1; j <= n; j++){ 42 int tt = 0; 43 for(int k = 1; k <= n; k++){ 44 if(i == k || j == k) continue; 45 else dd[++tt] = min(d[i][k], d[j][k]); 46 } 47 sort(dd+1, dd+1+tt); 48 for(int k = 1; k < tt; k++) 49 ans = (ans + 1ll * dd[k] * (tt-k)) % mod; 50 } 51 } 52 printf("%lld ", ans); 53 } 54 return 0; 55 }