题面
题意:
对于 f l o y e d floyed floyed算法, D i , j D_{i,j} Di,j表示最外层循环最小的能够求出来 d i s i , j dis_{i,j} disi,j的循环次数,计算 ∑ i = 1 n ∑ j = 1 n D i , j \sum_{i=1}^{n}{\sum_{j=1}^{n}{D_{i,j}}} ∑i=1n∑j=1nDi,j
思路
其实 D i , j D_{i,j} Di,j即为 i i i到 j j j的最短路路径上最小的不包含 i , j i,j i,j的最大下标。我们跑 n n n次 D i j k s t r a Dijkstra Dijkstra,每次更新路径上的最小的最大下标即可。复杂度 O ( n 2 l o g ( n ) ) O(n^2log(n)) O(n2log(n))。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline bool read(ll &num) {
char in;bool IsN=false;
in=getchar();
if(in==EOF) return false;
while(in!='-'&&(in<'0'||in>'9')) in=getchar();
if(in=='-'){ IsN=true;num=0;}
else num=in-'0';
while(in=getchar(),in>='0'&&in<='9'){
num*=10,num+=in-'0';
}
if(IsN) num=-num;
return true;
}
const ll N = 3005;
vector<pair<ll,ll> > G[N];
struct node{
ll id;
ll DIS;
};
ll dis[N],n,m,u,v,w,pre[N],mx[N];
bool vis[N];
bool operator<(node a,node b){
return a.DIS>b.DIS;
}
ll dij(ll st){
priority_queue<node> q;
memset(vis,0,sizeof(vis));
for(ll i=1;i<=n;i++) dis[i]=999999999999999;
for(ll i=1;i<=n;i++) pre[i]=999999999999999;
for(ll i=1;i<=n;i++) mx[i]=0;
dis[st]=0;
q.push({st,0});
while(!q.empty()){
node rt=q.top();q.pop();
ll u=rt.id;
if(vis[u]) continue;
vis[u]=1;
for(auto V:G[u]){
ll v=V.first;
ll w=V.second;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.push({v,dis[v]});
mx[v]=max(mx[u],u);
}
else if(dis[v]==dis[u]+w){
mx[v]=min(mx[v],max(mx[u],u));
}
if(u==st) mx[v]=0;
}
}
ll res=0;
for(int i=1;i<=n;i++) res+=mx[i];
return res;
}
int main(){
ll T;
read(T);
while(T--){
read(n);read(m);
for(int i=1;i<=n;i++) G[i].clear();
for(ll i=1;i<=m;i++){
read(u);read(v);read(w);
G[u].push_back({v,w});
G[v].push_back({u,w});
} ll ans=0;
for(ll i=1;i<=n;i++){
ans+=dij(i);
}
printf("%lld\n",ans%998244353);
}
return 0;
}