题目链接:https://www.acwing.com/problem/content/description/344/
这道题看起来像用SPFA的单源最短路,但是经过了特殊处理,SPFA会被卡。
所以就用到了缩点+拓扑最短路。
道路是无向的,所以可以将整个图分成若干个连通块,然后将这些连通块缩成点,整体上跑拓扑,在跑拓扑的过程中,用堆优化的dijkstra来处理每一个连通块中的最短路。注意块与块之间的联系方式:对所有的都处理dis,然后处理dis完了之后再看与前一个节点是否是同一个连通块中的点。
AC代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<queue> 4 #include<cstring> 5 using namespace std; 6 const int N=25005; 7 const int INF=0x3f3f3f3f3f; 8 queue<int> q; 9 priority_queue<pair<int,int> > q1; 10 int t,r,p,s; 11 int cnt,tot; 12 int head[N],c[N],vis[N],in[N],dis[N]; 13 struct node{ 14 int to,next,w; 15 }edge[N*10]; 16 void add(int u,int v,int w){ 17 edge[tot].to=v; 18 edge[tot].next=head[u]; 19 edge[tot].w=w; 20 head[u]=tot++; 21 } 22 void DFS(int u){ 23 for(int i=head[u];i!=-1;i=edge[i].next){ 24 int v=edge[i].to; 25 if(!c[v]){ 26 c[v]=c[u]; 27 DFS(v); 28 } 29 } 30 } 31 void toposort(){ 32 q.push(c[s]); 33 dis[s]=0; 34 for(int i=1;i<=cnt;i++){ 35 if(in[i]==0) q.push(i); 36 } 37 while(!q.empty()){ 38 int u=q.front(); q.pop(); 39 for(int i=1;i<=t;i++){ 40 if(c[i]==u) q1.push(make_pair(-dis[i],i)); 41 } 42 while(!q1.empty()){ 43 int u=q1.top().second; q1.pop(); 44 if(vis[u]) continue; 45 vis[u]=1; 46 for(int i=head[u];i!=-1;i=edge[i].next){ 47 int v=edge[i].to; 48 if(dis[u]+edge[i].w<dis[v]){ 49 dis[v]=dis[u]+edge[i].w; 50 if(c[u]==c[v]) q1.push(make_pair(-dis[v],v)); 51 } 52 if(c[u]!=c[v]&&--in[c[v]]==0) q.push(c[v]); 53 } 54 } 55 } 56 } 57 int main(){ 58 memset(dis,0x7f,sizeof(dis)); 59 memset(head,-1,sizeof(head)); 60 scanf("%d%d%d%d",&t,&r,&p,&s); 61 for(int i=1;i<=r;i++){ 62 int u,v,w; 63 scanf("%d%d%d",&u,&v,&w); 64 add(u,v,w); add(v,u,w); 65 } 66 for(int i=1;i<=t;i++){ 67 if(!c[i]){ 68 c[i]=++cnt; 69 DFS(i); 70 } 71 } 72 for(int i=1;i<=p;i++){ 73 int u,v,w; 74 scanf("%d%d%d",&u,&v,&w); 75 add(u,v,w); 76 in[c[v]]++; 77 } 78 toposort(); 79 for(int i=1;i<=t;i++){ 80 if(dis[i]>INF) printf("NO PATH "); 81 else printf("%d ",dis[i]); 82 } 83 return 0; 84 }