description
给出有向图的点数(n)和邻接矩阵(G),
求$$P=∑_{1≤x,y,z≤n,x≠y,y≠z}d(x,y,z)$$
其中(d(x,y,z))表示从(x)不经过(y)到(z)的最短路,如果无法到达则为(-1)
data range
[4≤n≤300,−1≤G_{i,j}≤10000,G_{i,i}=0
]
solution
首先你要知道(floyed)的本质是枚举中转点。
那么不经过(y)点的最短路矩阵相当于使用除(y)以外的点作为中转点更新后的邻接矩阵
于是考虑分治,递归到(l==r)时仅有节点(l)未被作为中转点
那么在做到([l,r])时,使用([l,mid])更新([mid+1,r]),使用([mid+1,r])更新([l,mid])即可。
Code
#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define Cpy(x,y) memcpy(x,y,sizeof(x))
#define Set(x,y) memset(x,y,sizeof(x))
#define FILE "a"
#define mp make_pair
#define pb push_back
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const int N=200010;
const int M=1000010;
const dd eps=1e-5;
const int inf=2147483647;
const ll INF=1ll<<60;
const ll P=100000;
il ll read(){
RG ll data=0,w=1;RG char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
return data*w;
}
il void file(){
srand(time(NULL)+rand());
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
}
int n;ll ans,g[20][305][305];
void divide(int l,int r,int d){
if(l==r){
for(RG int i=1;i<=n;i++)
for(RG int j=1;j<=n;j++)
if(i!=l&&j!=l)ans+=g[d-1][i][j];
return;
}
RG int mid=(l+r)>>1;
memcpy(g[d],g[d-1],sizeof(g[d]));
for(RG int k=mid+1;k<=r;k++)
for(RG int i=1;i<=n;i++)
if(k!=i)
for(RG int j=1;j<=n;j++)
if(k!=j&&i!=j&&g[d][i][k]!=-1&&g[d][k][j]!=-1)
if(g[d][i][j]==-1||g[d][i][j]>g[d][i][k]+g[d][k][j])
g[d][i][j]=g[d][i][k]+g[d][k][j];
divide(l,mid,d+1);
memcpy(g[d],g[d-1],sizeof(g[d]));
for(RG int k=l;k<=mid;k++)
for(RG int i=1;i<=n;i++)
if(k!=i)
for(RG int j=1;j<=n;j++)
if(k!=j&&i!=j&&g[d][i][k]!=-1&&g[d][k][j]!=-1)
if(g[d][i][j]==-1||g[d][i][j]>g[d][i][k]+g[d][k][j])
g[d][i][j]=g[d][i][k]+g[d][k][j];
divide(mid+1,r,d+1);
}
int main()
{
n=read();
for(RG int i=1;i<=n;i++)
for(RG int j=1;j<=n;j++)
g[0][i][j]=read();
divide(1,n,1);
printf("%lld
",ans);
return 0;
}