题目:
分析:
假设现在要求Du-v的值,结论:答案一定是 u 到 v 的最短路上(不算端点)编号最大的那个节点,根据Floyed算法流程容易证明;如果最短路有很多条呢,那么就取每个最大值的最小值;跑N遍迪杰斯特拉,不断更新Du-v即可;假设现在走x 到 v这条边,如果dis[u][v]被更新,那么(1)x != u时:D[u][v] = max(D[u][x],x),(2)x == u时:D[u][v] = D[u][x](因为端点不能算)
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e3+23;
const int mod = 998244353;
int T,n,m,u,v,w,cnt,head[maxn],a[maxn][maxn];
struct edge{
int to,nxt,w;
}e[maxn<<2];
LL dis[maxn][maxn];
void init(){
cnt = 0;
memset(a,0x3f,sizeof(a));
memset(dis,0x3f,sizeof(dis));
for(int i = 0;i <= n; ++i) head[i] = 0;
}
inline void add(int u,int v,int w){
e[++cnt] = (edge){v,head[u],w};
head[u] = cnt;
}
struct node{
LL len; int x;
node(LL _len,int _x){ len = _len; x = _x;}
friend bool operator<(node a,node b){
return a.len > b.len;
}
};
void diskrsta(int s){
dis[s][s] = 0; a[s][s] = 0;
priority_queue<node> q;
q.push(node(0,s));
while(!q.empty()){
node now = q.top(); q.pop();
if(dis[s][now.x] < now.len) continue;
for(int i = head[now.x];i > 0;i = e[i].nxt){
int v = e[i].to;
if(dis[s][v] > now.len + e[i].w){
dis[s][v] = now.len + e[i].w;
if(now.x != s) a[s][v] = max(now.x,a[s][now.x]);
else a[s][v] = a[s][now.x];
q.push(node(dis[s][v],v));
}
else if(dis[s][v] == now.len + e[i].w){ //多条最短路时
int ans;
if(now.x != s) ans = max(now.x,a[s][now.x]);
else ans = a[s][now.x];
if(ans < a[s][v]){
a[s][v] = ans;
q.push(node(dis[s][v],v)); //如果更新了注意还是要入队
}
}
}
}
}
int solve(){
LL res = 0;
for(int i = 1;i <= n; ++i){
diskrsta(i);
for(int j = 1;j <= n; ++j){
res += a[i][j];
if(res >= mod) res -= mod;
}
}
return (int)(res%mod);
}
int main(){
scanf("%d",&T);
while(T--){
init(); scanf("%d %d",&n,&m);
while(m--){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w); add(v,u,w);
}
printf("%d\n",solve());
}
return 0;
}