使用分治,考虑Floyd算法本来就是一个增量的过程。
记solve(l,r)表示加入除了l到r之间的点的APSP
然后分治
时间复杂度O(n^3logn)
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=305;
const int INF=1e9;
int n,w[N][N];
ll Ans;
inline void Solve(int l,int r,int dis[N][N]){
if (l==r){
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=j && i!=l && j!=l)
Ans+=dis[i][j]>=INF?-1:dis[i][j];
return;
}
int mid=(l+r)>>1;
int tmp[N][N];
for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) tmp[i][j]=dis[i][j];
for (int k=l;k<=mid;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
tmp[i][j]=min(tmp[i][j],tmp[i][k]+tmp[k][j]);
Solve(mid+1,r,tmp);
for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) tmp[i][j]=dis[i][j];
for (int k=mid+1;k<=r;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
tmp[i][j]=min(tmp[i][j],tmp[i][k]+tmp[k][j]);
Solve(l,mid,tmp);
}
int main(){
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
read(w[i][j]),w[i][j]=w[i][j]==-1?INF:w[i][j];
int tem[N][N];
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
tem[i][j]=w[i][j];
Solve(1,n,tem);
printf("%lld\n",Ans);
return 0;
}