给定一张有向图,起点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;
}
然后上代码