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\n",ans);
return 0;
}
原文地址:https://www.cnblogs.com/cjfdf/p/9703587.html
时间: 2024-10-11 12:08:15