2019年百度之星 - 初赛三B:最短路2【Dijkstra】

题目:

HDU---6714:最短路2

分析:

假设现在要求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;
}

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值