Book 最短路算法

用HDU2544整理一下最近学的最短路算法

1.Dijkstra算法

原理:集合S表示已经找到最短路径的点,d[]表示当前各点到源点的距离  

        初始时,集合里面只有源点,当每个点u进入集合S时,用d[u]+w[u][v]更新距离

        再重复这个步骤,选取S外所有点中d[]最小的进入集合

       直到所有的点都进入S集合

局限性:图的边权必须为正

复杂度:O(V*V),堆优化((E+V)logV)

(1)用邻接矩阵实现

 1 #include<iostream>  
 2 #include<cstdio>  
 3 #include<cstring> 
 4 #include <cmath> 
 5 #include<stack>
 6 #include<vector>
 7 #include<map> 
 8 #include<set>
 9 #include<queue> 
10 #include<algorithm>  
11 using namespace std;
12 
13 typedef long long LL;
14 const int INF = (1<<30)-1;
15 const int mod=1000000007;
16 const int maxn=10005;
17 int w[maxn][maxn],d[maxn],used[maxn];
18 int n,m;
19 
20 void dijkstra(int s){
21     memset(used,0,sizeof(used));
22     for(int i=1;i<=n;i++) d[i]=INF;
23     d[s]=0;
24     
25     for(int k=1;k<=n;k++){
26         int p,m=INF;
27         for(int i=1;i<=n;i++) if(!used[i]&&d[i]<m) m=d[p=i];
28         used[p]=1;
29         for(int i=1;i<=n;i++) d[i]=min(d[i],d[p]+w[p][i]);
30     }
31 }
32 
33 int main(){
34     int a,b,c;
35     while(scanf("%d %d",&n,&m)!=EOF&&n&&m){
36         for(int i=1;i<=n;i++){
37             for(int j=1;j<=n;j++){
38                 if(i==j) w[i][j]=0;
39                 else w[i][j]=INF;
40             }            
41         }
42         
43         for(int i=1;i<=m;i++){
44             scanf("%d %d %d",&a,&b,&c);
45             w[a][b]=w[b][a]=c;
46         }
47         dijkstra(1);
48         printf("%d\n",d[n]);

49     }
50     return 0;
51 }
View Code

(2)用邻接表实现

注意记得每次调用dijkstra()时,first[]置为-1

 1 #include<iostream>  
 2 #include<cstdio>  
 3 #include<cstring> 
 4 #include <cmath> 
 5 #include<stack>
 6 #include<vector>
 7 #include<map> 
 8 #include<set>
 9 #include<queue> 
10 #include<algorithm>  
11 using namespace std;
12 
13 typedef long long LL;
14 const int INF = (1<<30)-1;
15 const int mod=1000000007;
16 const int maxn=10005;
17 int d[maxn],used[maxn],firstt[maxn],nextt[maxn];
18 int n,m,ecnt;
19 
20 struct edge{
21     int v,cost;
22 } e[maxn];
23 
24 void dijkstra(int s){
25     memset(used,0,sizeof(used));
26     for(int i=1;i<=n;i++) d[i]=INF;
27     d[s]=0;
28     
29     for(int k=1;k<=n;k++){
30         int p,m=INF;
31         for(int i=1;i<=n;i++) if(!used[i]&&d[i]<m) m=d[p=i];
32         used[p]=1;
33         for(int i=firstt[p];i!=-1;i=nextt[i]){
34             int v=e[i].v;
35             if(d[v]>d[p]+e[i].cost) 
36             d[v]=d[p]+e[i].cost;
37         }
38     }
39 }
40 
41 void addedges(int u,int v,int w){
42     nextt[++ecnt]=firstt[u];
43     e[ecnt].v=v;
44     e[ecnt].cost=w;
45     firstt[u]=ecnt;    
46 }
47 
48 int main(){
49     int a,b,c;
50     while(scanf("%d %d",&n,&m)!=EOF&&n&&m){
51         ecnt=0;
52         memset(firstt,-1,sizeof(firstt));
53         
54         for(int i=1;i<=m;i++){
55             scanf("%d %d %d",&a,&b,&c);
56             addedges(a,b,c);
57             addedges(b,a,c);
58         }
59         dijkstra(1);
60         printf("%d\n",d[n]);
61     }
62     return 0;
63 }
View Code

 (3)堆(优先队列)优化
参看紫书上的解释,STL中的pair是专门将两个类型捆绑起来的,

而且pair定义了它自己的排序规则,先比较第一维,相等时才比较第二维,所以需要按照(d[i],i)的顺序组合。

 1 #include<iostream>  
 2 #include<cstdio>  
 3 #include<cstring> 
 4 #include <cmath> 
 5 #include<stack>
 6 #include<vector>
 7 #include<map> 
 8 #include<set>
 9 #include<queue> 
10 #include<algorithm>  
11 #define MP(a,b) make_pair(a,b)
12 using namespace std;
13 
14 typedef long long LL;
15 typedef pair<int,int> pii;
16 const int INF = (1<<30)-1;
17 const int mod=1000000007;
18 const int maxn=100005;
19 int d[maxn],firstt[maxn],nextt[maxn];
20 int n,m,ecnt;
21 
22 struct edge{
23     int v,cost;
24     friend bool operator < (edge a,edge b){
25         return a.cost>b.cost;
26     }
27 }e[maxn];
28 
29 void addedges(int u,int v,int c){
30     nextt[++ecnt]=firstt[u];
31     e[ecnt].v=v;
32     e[ecnt].cost=c;
33     firstt[u]=ecnt;
34 }
35 
36 void dijkstra(int s){
37     priority_queue<pii> pq;
38     for(int i=1;i<=n;i++) d[i]=INF;
39     d[s]=0;
40     pq.push(MP(d[s],1));
41     while(!pq.empty()){
42         pii x=pq.top();pq.pop();
43         if(d[x.second]<x.first) continue;//当前状态没有现在dis[]数组里面的优,所以不用再继续判断下去 
44         for(int i=firstt[x.second];i!=-1;i=nextt[i]){
45             int v=e[i].v;
46             if(d[v]>d[x.second]+e[i].cost){
47                 d[v]=d[x.second]+e[i].cost;
48                 pq.push(MP(d[v],v));
49             }            
50         }        
51     }
52 }
53 
54 int main(){
55     int a,b,c;
56     while(scanf("%d %d",&n,&m)!=EOF&&n&&m){
57         memset(firstt,-1,sizeof(firstt));
58         ecnt=0;
59         for(int i=1;i<=m;i++){
60             scanf("%d %d %d",&a,&b,&c);
61             addedges(a,b,c);
62             addedges(b,a,c);
63         }
64         dijkstra(1);
65         printf("%d\n",d[n]);
66     }
67     return 0;
68 }
View Code

 (4)用vector存图实现的

 1 #include<iostream>  
 2 #include<cstdio>  
 3 #include<cstring> 
 4 #include <cmath> 
 5 #include<stack>
 6 #include<vector>
 7 #include<map> 
 8 #include<set>
 9 #include<queue> 
10 #include<algorithm>  
11 using namespace std;
12 
13 typedef long long LL;
14 const int INF = (1<<30)-1;
15 const int mod=1000000007;
16 const int maxn=10005;
17 int d[maxn];
18 
19 typedef struct edge{
20     int to,distance;
21     edge(){}
22     edge(int to,int distance) :to(to),distance(distance){}
23 };
24 typedef pair<int,int> P;
25 vector<edge> G[maxn];
26 int n,m,k;
27 
28 void dijkstra(int s){
29     
30     priority_queue<P,vector<P> ,greater<P> > q;
31     for(int i=0;i < n;i++) d[i]=INF;
32     d[s]=0;
33     q.push(P(0,s));
34     
35     while(!q.empty()){
36         P p=q.top();q.pop();
37         int v=p.second;
38         if(d[v]<p.first) continue;
39         for(int i=0;i<G[v].size();i++){
40             edge e=G[v][i];
41         
42             if(d[e.to] > d[v]+e.distance){
43             
44                 d[e.to] = d[v]+e.distance;
45                 q.push(P(d[e.to],e.to));
46             }    
47         }
48     }
49 }
50 
51 int main(){
52     while(scanf("%d %d",&n,&m)!=EOF){
53         if(n==0&&m==0) break;
54             for(int i=0;i<n;i++) G[i].clear();
55         while(m--){
56             int u,v,w;
57             scanf("%d %d %d",&u,&v,&w);
58             u--;v--;
59             G[u].push_back(edge(v,w));
60             G[v].push_back(edge(u,w));            
61         }
62         dijkstra(0);
63         printf("%d\n",d[n-1]);
64     }
65         
66     return 0;
67 }
View Code

 

2.Bellman_Ford算法

原理:对于图G(V,E),Bellman_Ford是对整个图进行V-1次松弛,每次松弛检查每条边,如果d[v]>d[u]+cost,那么则更新d[v]

应用:可以用来判断负环, 如果没有负权回路的话,那么任意两点间的路径最多经过n-2个点,

         即最多松弛n-1次,如果有负权回路,那么第n次松弛操作仍然会成功。

复杂度:O(VE)

 1 #include<iostream>  
 2 #include<cstdio>  
 3 #include<cstring> 
 4 #include <cmath> 
 5 #include<stack>
 6 #include<vector>
 7 #include<map> 
 8 #include<set>
 9 #include<queue> 
10 #include<algorithm>  
11 using namespace std;
12 
13 typedef long long LL;
14 const int INF = (1<<30)-1;
15 const int mod=1000000007;
16 const int maxn=100005;
17 int d[maxn];
18 int n,m,ecnt;
19 
20 struct edge{
21     int u,v,cost;
22 } e[maxn];
23 
24 void addedges(int u,int v,int c){
25     e[++ecnt].u=u;
26     e[ecnt].v=v;
27     e[ecnt].cost=c;    
28 }
29 
30 void Bellman_Ford(int s){
31     for(int i=1;i<=n;i++) d[i]=INF;
32     d[s]=0;
33     
34     for(int i=1;i<n;i++){
35         for(int j=1;j<=ecnt;j++){
36             if(d[e[j].v]>d[e[j].u]+e[j].cost)
37             d[e[j].v]=d[e[j].u]+e[j].cost;
38         }
39     }
40 }
41 
42 int main(){
43     int a,b,c;
44     while(scanf("%d %d",&n,&m)!=EOF&&n&&m){
45         ecnt=0;
46         for(int i=1;i<=m;i++){
47             scanf("%d %d %d",&a,&b,&c);
48             addedges(a,b,c);
49             addedges(b,a,c);
50         }
51         Bellman_Ford(1);
52         printf("%d\n",d[n]);
53     }
54     return 0;
55 }
View Code

 

转载于:https://www.cnblogs.com/wuyuewoniu/p/4419535.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值