最短路图(dijkistra)

给定一张有向图,起点s,终点t

求s到t的所有最短路组成的DAG(没有负环的最短路图一定是DAG)

之前蒟蒻的我使用前缀指针然后dfs。。。。其实有更为简洁巧妙地方法

首先需要建一张正向图(这不是废话吗),然后还需要建一张反向图

dis1[] 表示正向图上点s到所有点的最短距离,dis2[]表示反向图上点t到所有点的最短距离

考虑正向图上的一条边(edge){u,v,w}

如何判断这条边需不需要加入最短路图呢?

很显然只需要满足

dis1[u]+w+dis2[v]==dis1[t] 就ok,为什么呢,画一张图来看看

这样就很明显了吧!

#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
struct graph{
    int head[10000],nxt[30000],to[30000],wei[30000],cnt;
    void clear(){
        for(int i=0;i<10000;i++)head[i]=0;
        for(int i=0;i<30000;i++)nxt[i]=0,to[i]=0,wei[i]=0;
        cnt=1;
    }
    void add(int u,int v,int w){
        nxt[++cnt]=head[u];
        to[cnt]=v;
        head[u]=cnt;
        wei[cnt]=w;
    }
    graph(){clear();}
};
struct node{
    int p,d;
    bool operator < (const node& other)const{
        return d>other.d;
    }
    bool operator > (const node& other)const{
        return d<other.d;
    }
};
int n,m;
struct edge{
    int u,v,w;
};
edge a[30000];
int dis1[10000],dis2[10000];
//dis1: s为起点的单源最短路
//dis2: t为起点的单源最短路
graph dag;
bool vis[10000];
priority_queue<node> q;
void dijkistra(int s,int* dis,graph& g){
    for(int i=1;i<=n;i++)vis[i]=false,dis[i]=0x3f3f3f3f;
    while(!q.empty())q.pop();
    dis[s]=0;
    q.push((node){s,0});
    while(!q.empty()){
        node top=q.top();
        q.pop();
        int u=top.p;
        if(vis[u])continue;
        vis[u]=true;
        for(int i=g.head[u];i;i=g.nxt[i]){
            int v=g.to[i];
            if(dis[v]>dis[u]+g.wei[i]){
                dis[v]=dis[u]+g.wei[i];
                q.push((node){v,dis[v]});
            }
        }
    }
}
graph g,fg;
int s,t;
int main(){
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
        g.add(a[i].u,a[i].v,a[i].w);
        fg.add(a[i].v,a[i].u,a[i].w);
    }
    dijkistra(s,dis1,g);
    dijkistra(t,dis2,fg);
    for(int i=1;i<=m;i++){
        int u=a[i].u,v=a[i].v,w=a[i].w;
        if(dis1[u]+w+dis2[v]==dis1[t]){
            dag.add(u,v,w);
            printf("%d->%d\n",u,v);
        }
    }
    return 0;
}

然后上代码

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值