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 }  
时间: 2024-12-17 12:54:16

NO2——最短路径的相关文章

ACM: HDU 3790 最短路径问题-Dijkstra算法

HDU 3790 最短路径问题 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description 给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的. Input 输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p.最后一行是

最短路径算法专题1----弗洛伊德

由于最短路径算法我认为比较重要,所以分成几个专题来慢慢细化去磨它,不能一口气吃个胖子嘛. 首先在说算法之前,先说清楚什么叫做最短路径. 题目一般会给你一张图,然后告诉你很多地方,然后告诉你各个地方之间的路程有多远,要你求出,两点间的最短距离,注意,题目给出的两点间的距离未必是最短的,可能通过第三个点转换之后达到更短.实际其实也是这样的,有时候两个地方并没有直线的道路只有曲线的绕路. 算法的思路: 1.用二维数组列出所有的距离,达到不了的用最大距离表示,如9999999 2.循环数组上面的每一个点

postgresql+postgis+pgrouting实现最短路径查询(1)---线数据的处理和建立拓扑

准备一个线shp数据,并将其导入postgres里面,postgres安装postgis和pgrouting两个插件(方法见http://www.cnblogs.com/nidaye/p/4553522.html).线数据的字段如下:注意字段的名称,省的出现不必要的麻烦. 1.ALTER TABLE beijing_line ADD COLUMN source integer; ALTER TABLE beijing_line ADD COLUMN target integer; ALTER T

算法导论——最短路径Dijkstra算法

package org.loda.graph; import org.loda.structure.IndexMinQ; import org.loda.structure.Stack; import org.loda.util.In; /** * * @ClassName: Dijkstra * @Description: Dijkstra最短路径算法--贪心算法 * @author minjun * @date 2015年5月27日 下午4:49:27 * */ public class D

最短路径(四)—Bellman-Ford的队列优化(邻接表)

上一节我们写了Bellman-Ford算法解决负权边的问题: 邻接表存储图: n个顶点,m条边. 数组实现邻接表.对每一条边进行1-m编号.用u,v,w三个数组来记录每条边的信息,即u[i],v[i],w[i]表示第i条边是从第 u[i]号顶点到v[i]号顶点且权值为w[i]. first数组的1-n号单元格分别用来存储1-n号顶点的第一条边的编号,初始的时候因为没有边加入所有都是-1.即first[u[i]]保存顶点u[i]的第一条边的编号,next[i]存储"编号为i的边"的&qu

最短路径(Floyd法)

最短路径法: 算法的主要思想是:单独一条边的路径也不一定是最佳路径. 从任意一条单边路径开始.所有两点之间的距离是边的权的和,(如果两点之间没有边相连, 则为无穷大). 对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短.如果是更新它. 先把所有的结果都计算出来放在数组里面,然后根据需要输出所需要的两点之间的最短路径.用了三个循环来实现 还有一个要Mark一下的是:不如一个数组s[i][j]:那可以用这个数组来存放三个数 i,j和s[i][j]:

最短路径算法——迪杰斯特拉算法(Dijkstra)

图结构中应用的最多的就是最短路径的查找了,关于最短路径查找的算法主要有两种:迪杰斯特拉算法(Dijkstra)和Floyd算法. 其中迪杰斯特拉算法(Dijkstra)实现如下: 原理就是不断寻找当前的最优解: void main() { int V[Max][Max]={0,8,32,Infinity,Infinity, 12,0,16,15,Infinity, Infinity,29,0,Infinity,13, Infinity,21,Infinity,0,7, Infinity,Infi

[BZOJ 1576] 安全路径 最短路径树 路径压缩

题意 给定一张 n 个点 m 条边的图, 保证对于任意的点 i , 从点 1 到点 i 的最短路唯一. 对于任意的点 i , 询问: 将 1 到 i 的最短路中最后一条边删去之后, 从 1 到 i 的最短路 . n <= 100000, m <= 200000 . 分析 首先跑 Dijsktra , 构建出最短路径树. 接下来考虑每条非树边 E[p] = (u, v, d) 对答案的影响, 它能且仅能影响到点 u, v 之上, LCA(u, v) 之下的点的答案. (包括 u, v, 不包括

四大最短路径算法比较

  Floyd Dijkstra Bellman-Ford 队列优化的Bellman-ford 空间复杂度 O(N²) O(M) O(M) O(M) 时间复杂度 O(N3) O((M+N)logN) O(NM) O(NM) 适用情况 稠密图,和顶点关系密切 稠密图,和顶点关系密切 稀疏图,和边关系密切 稀疏图,和边关系密切 负权 可以解决 不能解决 可以解决 可以解决 注1:N为定点数,M为边数 注2:  Floyd的编码复杂度较小,均摊到每个点上的时间复杂度并不算太高,如果是求所有点对间的最短