NO2——最短路径

【Dijkstra算法】

  • 复杂度O(n2
  • 权值必须非负
 1 /*    求出点beg到所有点的最短路径    */ 
 2 //    邻接矩阵形式 
 3 //    n:图的顶点数
 4 //    cost[][]:邻接矩阵 
 5 //    pre[i]记录beg到i路径上的父结点,pre[beg]=-1
 6 //    返回:各点的最短路径lowcost[]以及路径pre[]
 7 const int maxn=1010; 
 8 const int INF=0x3f3f3f3f;        //防止后面溢出,这个不能太大 
 9 bool vis[maxn]; 
10 int pre[maxn]; 
11 void Dijkstra(int cost[][maxn],int lowcost[],int n,int beg) 
12 { 
13   for(int i=0;i<n;i++)       //点的编号从0开始
14   { 
15     lowcost[i]=INF;vis[i]=false;pre[i]=-1; 
16   } 
17   lowcost[beg]=0; 
18   for(int j=0;j<n;j++) 
19   { 
20     int k=-1; 
21     int Min=INF; 
22     for(int i=0;i<n;i++) 
23       if(!vis[i]&&lowcost[i]<Min) 
24       { 
25         Min=lowcost[i]; 
26         k=i; 
27       } 
28     if(k==-1)break; 
29     vis[k]=true; 
30     for(int i=0;i<n;i++) 
31       if(!vis[i]&&lowcost[k]+cost[k][i]<lowcost[i]) 
32       { 
33         lowcost[i]=lowcost[k]+cost[k][i]; 
34         pre[i]=k; 
35       } 
36   } 
37 } 

【Dijkstra算法+堆优化】

  • 复杂度O(E*logE)
  • 使用优先队列优化Dijkstra算法
 1 //注意对vector<Edge>E[MAXN]进行初始化后加边
 2 const int INF=0x3f3f3f3f; 
 3 const int maxn=1000010; 
 4 struct qnode 
 5 { 
 6       int v; 
 7       int c; 
 8       qnode(int _v=0,int _c=0):v(_v),c(_c){} 
 9       bool operator <(const qnode &r)const 
10       { 
11         return c>r.c; 
12       } 
13 }; 
14 struct Edge 
15 { 
16       int v,cost; 
17       Edge(int _v=0,int _cost=0):v(_v),cost(_cost){} 
18 }; 
19 vector<Edge>E[maxn]; 
20 bool vis[maxn]; 
21 int dist[maxn]; 
22 void Dijkstra(int n,int start)        //点的编号从1开始 
23 { 
24     memset(vis,false,sizeof(vis)); 
25       for(int i=1;i<=n;i++)dist[i]=INF; 
26       priority_queue<qnode>que; 
27       while(!que.empty())que.pop(); 
28       dist[start]=0; 
29       que.push(qnode(start,0)); 
30       qnode tmp; 
31       while(!que.empty()){
32           tmp=que.top(); 
33         que.pop(); 
34         int u=tmp.v; 
35         if(vis[u])continue; 
36         vis[u]=true; 
37         for(int i=0;i<E[u].size();i++){ 
38               int v=E[tmp.v][i].v; 
39               int cost=E[u][i].cost; 
40               if(!vis[v]&&dist[v]>dist[u]+cost){ 
41                 dist[v]=dist[u]+cost; 
42                 que.push(qnode(v,dist[v])); 
43               } 
44         } 
45       } 
46 } 
47 void addedge(int u,int v,int w) 
48 {
49     E[u].push_back(Edge(v,w)); 
50 } 

【Bellman-ford算法】

  • 复杂度O(V*E)
  • 可以处理负边权图
 1 //可以判断是否存在负环回路
 2 //返回true,当且仅当图中不包含从源点可达的负权回路 
 3 //vector<Edge>E;
 4 //先E.clear()初始化,然后加入所有边 
 5 const int INF=0x3f3f3f3f; 
 6 const int maxn=550; 
 7 int dist[maxn]; 
 8 struct Edge 
 9 { 
10   int u,v; 
11   int cost; 
12   Edge(int _u=0,int _v=0,int _cost=0):u(_u),v(_v),cost(_cost){}     //构造函数 
13 }; 
14 vector<Edge>E; 
15 bool bellman_ford(int start,int n)    //点的编号从1开始 
16 { 
17   for(int i=1;i<=n;i++)dist[i]=INF; 
18   dist[start]=0; 
19   for(int  i=1;i<n;i++)            //最多做n-1次 
20   { 
21     bool flag=false; 
22     for(int j=0;j<E.size();j++) 
23     { 
24       int u=E[j].u; 
25       int v=E[j].v; 
26       int cost=E[j].cost; 
27       if(dist[v]>dist[u]+cost) 
28       { 
29         dist[v]=dist[u]+cost; 
30         flag=true; 
31       } 
32     } 
33     if(!flag)return  true;    //没有负环回路 
34   } 
35   for(int j=0;j<E.size();j++) 
36     if(dist[E[j].v]>dist[E[j].u]+E[j].cost) 
37       return false;    //有负环回路 
38   return true;        //没有负环回路 
39 } 

【SPFA算法】

  • 复杂度O(K*E)
 1 //这个是队列实现,有时候改成栈实现会更加快,很容易修改 
 2 //这个复杂度是不定的 
 3 const int maxn=1010; 
 4 const int INF=0x3f3f3f3f; 
 5 struct Edge 
 6 { 
 7   int v; 
 8   int cost; 
 9   Edge(int _v=0,int _cost=0):v(_v),cost(_cost){} 
10 }; 
11 vector<Edge>E[maxn]; 
12 void addedge(int u,int v,int w) 
13 { 
14   E[u].push_back(Edge(v,w)); 
15 } 
16 bool vis[maxn];                //在队列标志 
17 int cnt[maxn];                //每个点的入队列次数 
18 int dist[maxn]; 
19 bool SPFA(int start,int n) 
20 { 
21   memset(vis,false,sizeof(vis)); 
22   for(int i=1;i<=n;i++)dist[i]=INF; 
23   vis[start]=true; 
24   dist[start]=0; 
25   queue<int>que; 
26   while(!que.empty())que.pop(); 
27   que.push(start); 
28   memset(cnt,0,sizeof(cnt)); 
29   cnt[start]=1; 
30   while(!que.empty()) 
31   { 
32     int u=que.front(); 
33     que.pop(); 
34     vis[u]=false; 
35     for(int i=0;i<E[u].size();i++) 
36     { 
37       int v=E[u][i].v; 
38       if(dist[v]>dist[u]+E[u][i].cost) 
39       { 
40         dist[v]=dist[u]+E[u][i].cost; 
41         if(!vis[v]) 
42         { 
43           vis[v]=true; 
44           que.push(v); 
45           if(++cnt[v]>n)return false;         //cnt[i]为入队列次数,用来判定是否存在负环回路 
46         } 
47       } 
48     } 
49   } 
50   return true; 
51 } 

Floyd-Warshall算法

  • 复杂度O(n3
  • 边权非负
 1 #include<cstdio>  
 2 using namespace std;  
 3 #define INF 1e9  
 4 const int maxn=100+10;  
 5 int n,m;                //点数,边数,点从0到n-1编号  
 6 int dist[maxn][maxn];    //记录距离矩阵  
 7 int path[maxn][maxn];    //path[i][j]=x表示i到j的路径上(除i外)的第一个点是x.  
 8 void init()  
 9 {  
10     for(int i=0;i<n;i++)  
11     for(int j=0;j<n;j++)  
12     {  
13         dist[i][j] = i==j ? 0 : INF;    //其实这里d[i][j]应该还要通过输入读数据的  
14         path[i][j] = j;  
15     }  
16   
17     //读取其他dist[i][j]的值  
18 }  
19 void floyd()  
20 {  
21     for(int k=0;k<n;k++)  
22     for(int i=0;i<n;i++)  
23     for(int j=0;j<n;j++)  
24     if(dist[i][k]<INF && dist[k][j]<INF )  
25     {  
26         if(dist[i][j]>dist[i][k]+dist[k][j])  
27         {  
28             dist[i][j] = dist[i][k]+dist[k][j];  
29             path[i][j] = path[i][k];  
30         }  
31         else if(dist[i][j] == dist[i][k]+dist[k][j] &&path[i][j]>path[i][k])  
32         {  
33             path[i][j] = path[i][k];  //最终path中存的是字典序最小的路径  
34         }  
35     }  
36 }  
37   
38 int main()  
39 {  
40     //读n和m  
41     init();  
42     //读m条边  
43     floyd();  
44     //输出所求最短路径距离  
45     return 0;  
46 }  
原文地址:https://www.cnblogs.com/xzxl/p/7295666.html