dijkstra——邮递员送信(反图最短路)

P1629 邮递员送信 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 

从1到其他点的距离就是简单的dijkstra的板子,但是因为是有向边,所以返回的时候不会走原来的路,必须找到从要返回的k点到1点的最短路。

刚开始我想的是返回时求n-1次dijkstra,但是会超时,所以换一个思路。

 

因为返回时相当于多个起点指向一个终点,因此我们可以转化成一个终点到多个起点的最短路问题。也就是转化成了1到n-1个点的返回时的最短路。

 

对于反图这个概念,刚开始我是不理解的。我认为因为是有向边,所以反图输入的方向不可能被走,不理解是怎样运行的。

 

然后看到了这个文章(39条消息) 最短路-反向建边(附图详解)_codeducker的博客-CSDN博客,明白了自己的问题。反图的意义是将多起点指向一个终点的问题转化为一个终点指向多个起点。如果原图中3到1的最短路是3->2->6->1,那么反图中存的就是1-6-2-3,这个路,距离是一样的,而且意义转化也是一样的,因此我们就可以让1跑整个反图,求出到每个点的距离,也就转化成了每个点到1的最短距离。

 

1.可以用两个数组,分别存储正图与反图。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=2e5+100,M=2e3+100;;
 4 int n,m,idx,h[M],rh[M],dist[N];
 5 bool st[N];
 6 
 7 struct EDG
 8 {
 9     int to,ne,w;
10 }e[N];
11 
12 void add(int x,int y,int v,int num)
13 {
14     idx++;
15     if(num==1)
16         e[idx].to=y,e[idx].ne=h[x],e[idx].w=v,h[x]=idx;
17     else 
18         e[idx].to=y,e[idx].ne=rh[x],e[idx].w=v,rh[x]=idx;
19 }
20 
21 typedef pair<int,int> pii;
22 priority_queue<pii,vector<pii>,greater<pii> >q; 
23 void dijkstra(int u,int num)
24 {
25     memset(dist,0x3f,sizeof dist);
26     memset(st,0,sizeof st);
27     q.push({0,u});
28     dist[u]=0;
29     while(q.size())
30     {
31         pii sta=q.top();q.pop();
32         int x=sta.second,distance=sta.first;
33         if(st[x])continue;
34         st[x]=1;
35         
36         int j;
37         if(num==1)j=h[x];
38         else j=rh[x];
39         for(int i=j;i;i=e[i].ne)
40         {
41             int y=e[i].to;
42             if(dist[y]>distance+e[i].w)
43             {
44                 dist[y]=distance+e[i].w;
45                 if(!st[y])q.push({dist[y],y});
46             }
47         }
48         
49     }
50     
51 }
52 
53 
54 
55 int main()
56 {
57     scanf("%d%d",&n,&m);
58     
59     for(int i=1;i<=m;i++)
60     {
61         int x,y,v;
62         scanf("%d%d%d",&x,&y,&v);
63         add(x,y,v,1);add(y,x,v,2);
64     }
65     
66     long long ans=0;
67     dijkstra(1,1);    //正图 
68     for(int i=1;i<=n;i++)ans+=dist[i];
69 
70     dijkstra(1,2);    //反图 
71     for(int i=2;i<=n;i++)ans+=dist[i];
72     
73     printf("%lld\n",ans);
74     
75     
76     
77     return 0;
78 }
View Code

 

2.也可以用一个数组,反图的编号都加n

add(x,y,w) add(y+n,x+n,w)

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=2e5+100,M=1e3+100;;
 4 int n,m,idx,h[M],rh[M],dist[N];
 5 bool st[N];
 6 
 7 struct EDG
 8 {
 9     int to,ne,w;
10 }e[N];
11 
12 
13 
14 void add(int x,int y,int v)
15 {
16     idx++;
17     e[idx].to=y,e[idx].ne=h[x],e[idx].w=v,h[x]=idx;
18 }
19 
20 typedef pair<int,int> pii;
21 priority_queue<pii,vector<pii>,greater<pii> >q; 
22 void dijkstra(int u)
23 {
24     memset(dist,0x3f,sizeof dist);
25     memset(st,0,sizeof st);
26     q.push({0,u});
27     dist[u]=0;
28     while(q.size())
29     {
30         pii sta=q.top();q.pop();
31         int x=sta.second,distance=sta.first;
32         if(st[x])continue;
33         st[x]=1;
34         
35         
36         for(int i=h[x];i;i=e[i].ne)
37         {
38             int y=e[i].to;
39             if(dist[y]>distance+e[i].w)
40             {
41                 dist[y]=distance+e[i].w;
42                 if(!st[y])q.push({dist[y],y});
43             }
44         }
45         
46     }
47     
48 }
49 
50 
51 
52 int main()
53 {
54     scanf("%d%d",&n,&m);
55     
56     for(int i=1;i<=m;i++)
57     {
58         int x,y,v;
59         scanf("%d%d%d",&x,&y,&v);
60         add(x,y,v);add(y+n,x+n,v);
61     }
62     
63     long long ans=0;
64     dijkstra(1);
65     for(int i=1;i<=n;i++)ans+=dist[i];
66 
67     dijkstra(1+n);
68     for(int i=2+n;i<=n*2;i++)ans+=dist[i];
69     
70     printf("%lld\n",ans);
71     
72     
73     
74     return 0;
75 }
View Code

 

posted @ 2022-03-03 11:07  wellerency  阅读(110)  评论(0编辑  收藏  举报