迪杰斯特拉 优先队列 模板

完善刘佳汝紫书P361、P362的代码

邻接矩阵存稀疏图太耗内存了  这种写法感觉不错 copy一下

写的有点急 可能有的地方有错误 有些地方还可以在优化   p数组记录路径未验证  以后还会在写一个用 pair 的迪杰斯特拉写法

  1 #include <stdio.h>
  2 #include <math.h>
  3 #include <string.h>
  4 #include <stdlib.h>
  5 #include <iostream>
  6 #include <sstream>
  7 #include <algorithm>
  8 #include <string>
  9 #include <queue>
 10 #include <vector>
 11 using namespace std;
 12 const int maxn= 1e5+10;
 13 const int maxm= 1e4+10;
 14 const int inf = 1008611;
 15 typedef long long ll;
 16 int n,m,s;                      //n个点1~n   m 条边    起点 s
 17 int d[maxn],done[maxn],p[maxn]; //d[i]表示i点到起点s的最短路距离
 18                                 //done[u]==1表示u点到起点点s的最短路已经找到
 19                                 //p[i]表示起点s到i的最短路径与i点相连的上一条边
 20 struct edge                //边结构体
 21 {
 22     int from,to,dis;
 23 };
 24 vector<edge> edges;     //边集 无向图 边数*2
 25 vector<int> g[maxn];    //g数组存的是边的序号
 26 struct mindis           //压入优先队列的结构体 因为d[u]和u要绑定起来 才可标记 u是否已确定最短路
 27 {
 28     int d,u;
 29     bool operator <(const mindis& rhs)const{
 30         return d>rhs.d;         //距离最小值优先 距离相等无所谓 随便一个先出 边权是正的 两个会依次访问 不会影想结果
 31     }
 32 };
 33 void init(int n)                //每次输入数据清空容器
 34 {
 35     for(int i=0;i<=n;i++)
 36         g[i].clear();
 37     edges.clear();
 38 }
 39 void addedge(int from,int to,int dis)      //加边操作
 40 {
 41     edges.push_back((edge){from,to,dis});   //将边压入边集
 42     int k=edges.size();
 43     g[from].push_back(k-1);                 //k-1为边序号 以后调用边集数组要从下标0开始 所以边的编号从0开始 将边序号压入已from为起点的数组
 44 }
 45 void dijkstra(int s)     //主算法
 46 {
 47     for(int i=0;i<=n;i++)      //把距离初始化为 inf  不能用memset  自己估算一下路径最长有多长 inf定义大一点就好
 48         d[i]=inf;
 49     d[s]=0;                     //到自己的最短距离直接设为0
 50     priority_queue<mindis> q;   //优先队列 小顶堆 最小值优先
 51     q.push((mindis){0,s});
 52     memset(done,0,sizeof(done));  //初始化数组
 53     memset(p,-1,sizeof(p));
 54     while(!q.empty())              //队列非空
 55     {
 56         mindis x=q.top();           //取当前最小值
 57         q.pop();
 58         int u=x.u;
 59         if(done[u]==1)              //已确定路径直接跳过
 60             continue;
 61         done[u]=1;                  //标记 已确定
 62         for(int i=0;i<g[u].size();i++)
 63         {
 64             edge e =edges[g[u][i]];  //g[u][i]表示以u为起点的第i条边在边集edges中的下标
 65             if(d[e.to]>d[u]+e.dis)     //满足条件更新距离
 66             {
 67                 d[e.to]=d[u]+e.dis;
 68                 p[e.to]=g[u][i];       //保存路径
 69                 q.push((mindis){d[e.to],e.to});  //把更新完的值压入队列
 70             }
 71         }
 72     }
 73 }
 74 int main()
 75 {
 76     scanf("%d %d %d",&n,&m,&s);
 77     init(n);
 78     int u,v,w;
 79     for(int i=0;i<m;i++)
 80     {
 81         scanf("%d %d %d",&u,&v,&w);
 82         addedge(u,v,w);
 83         addedge(v,u,w);             //无向图相互可达 有向图一次就好
 84     }
 85     dijkstra(s);
 86 //    for(int i=0;i<edges.size();i++)
 87 //    {
 88 //        printf("%d %d %d %d\n",i,edges[i].from,edges[i].to,edges[i].dis);
 89 //    }
 90 //    for(int i=1;i<=n;i++)
 91 //    {
 92 //        printf("%d\n",i);
 93 //        for(int j=0;j<g[i].size();j++)
 94 //            printf("%d\n",g[i][j]);
 95 //        printf("\n");
 96 //    }
 97     for(int i=1;i<=n;i++)           //打印每个点到起点s的最短距离
 98         printf("%d\n",d[i]);
 99     return 0;
100 }
101 //样例
102 //6 9 5
103 //5 4 6
104 //5 1 3
105 //5 2 5
106 //4 1 4
107 //1 2 1
108 //4 3 4
109 //1 3 2
110 //2 3 3
111 //3 6 4

欢迎交流!!~~~

posted @ 2017-10-23 21:21  灬从此以后灬  阅读(525)  评论(1编辑  收藏  举报