BZOJ 2200 道路与航线(缩点+最短路+拓扑排序)

题目链接: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\n");
81         else printf("%d\n",dis[i]);
82     }
83     return 0;
84 }
AC代码

 

posted @ 2020-11-03 19:35  dfydn  阅读(78)  评论(0编辑  收藏  举报