【板子】最短路算法

1.迪杰斯特拉算法

包含一般实现和利用优先队列的实现

/*迪杰斯特拉最短路模板
 *迪杰斯特拉算法也仅仅是进行松弛的一种策略,适应的条件是
 *图中不能含有负边权,因为对于边权为负的那条边来说箭头处的
 *那个顶点的算法会出现问题。
 * distTo[]和edgeTo[]是迪杰斯特拉算法需要的两个数据结构
 * 另外还需要一个标志数组用于判断顶点的最短路径是否已经被求出来
 * 对于无向图来说,算法实现跟有向图其实是一致的,因为,一个顶点
 * 最短路径被求出来时就不可能再被松弛了
 * 
 * 普通实现如下:
 * (1)初始化三个数组并单独初始化源顶点
 * (2)循环n次找出顶点到其他n个点的距离
 *          a、从distTo中找到最小的那个即为目前已求出的最短路径
 *          b、用刚才的顶点更新其相邻顶点的最短路径和路径
 *             (往往这个地方需要用到图的存储结构:邻接表或者邻接矩阵)
 * 
 * 基本上迪杰斯特拉算法的实现必然要依赖于图结构,因为松弛由
 * 最近开始到最远,那么必然要图结构来实现松弛这个过程
 * 下面为CPP中用优先队列实现的源代码
 * 
 * cpp中priority_queue中使用greater时为小顶堆
 */
//P4779
//本实现中顶点的编号从1开始
//邻接表用vector来实现

#include 
#include 
#include 
#include 
#include  

using namespace std;

//下面这部分为邻接表的实现
struct Edge
{
    int cost, to;
};

vector<Edge> graph[100009];

//该数组记录源点到其他每一点的距离
int distTo[100009];
bool is_s[100009]; //这里已经初始化为false
int prenode[100009]; //这个数组用来还原路径

typedef pair<int, int> P;

int n;
void dijkstra(int);

int main()
{
    //把图结构建立起来
    int m, s;
    scanf("%d %d %d", &n, &m, &s);
    for(int i = 0; i < m; ++i)
    {
        int s;
        Edge temp;
        scanf("%d %d %d", &s, &temp.to, &temp.cost);
        graph[s].push_back(temp);
    }

    dijkstra(s);

    for(int i = 1; i <= n; ++i)
        printf("%d ", distTo[i]);

    return 0;
}

void dijkstra(int s)
{
    //first是最短距离,second是顶点的编号
    priority_queue<P, vector<P>, greater<P> > que;
    fill(distTo, distTo+100009, 1e9+1);
    fill(prenode, prenode+100009, -1);
    distTo[1] = 0;
    que.push(make_pair(0, 1));

    while(!que.empty())
    {
        P temp = que.top(); que.pop();
        int v = temp.second;

        //这个地方明白了,对于同一个顶点,优先队列中可能存在多个pair,先进优先队列的
        //因为更新较早,distTo可能较大,后进的,因为更新晚,因此比较小,不然也进不去。
        //对于某个顶点v来说,较小的distTo进了优先队列后,则v的distTo不可能被更新的更大。
        //所有已经从优先队列退出得顶点不可能再被push进去,
        if(distTo[v] < temp.first) continue;

        for(int i = 0; i < graph[v].size(); ++i)
        {
            int to = graph[v][i].to;
            int cost = graph[v][i].cost;
            if(distTo[to] > distTo[v] + cost)
            {
                distTo[to] = distTo[v] + cost;
                que.push(make_pair(distTo[to], to));
                prenode[to] = v;
            }
        }
    }
}



/**
//下面为迪杰斯特拉算法的一般实现
//大部分数组都设置成公共变量,因此可以在本函数中访问
//只要给 出源点,就可以把distTo数组设置好
void dijkstra(int s)
{
    //初始化
    fill(is_s, is_s+100009, false);
    fill(distTo, distTo+100009, int(1e9 + 1)); //科学表示法表示的时浮点数
    fill(prenode, prenode+100009, 0);
    distTo[1] = 0;

    for(int i = 0; i < n; ++i)
    {
        
        long tmp_min = (int)1e9+1, k = -1;//tmp_min的初始值应该是等于distTo初始化时的最大值,不应该更大,更大的话这个循环会出问题
        for(int j = 1; j <= n; ++j)
        {
            if(distTo[j] < tmp_min && is_s[j] == false)
            {
                k = j; tmp_min = distTo[j];
            }
        }
		if(k == -1) break; //加上这样一句很重要,不然程序就会出错,当k == -1说明了余下的点都是源点不可达的 因不用再求解了
        is_s[k] = true;
        for(int i = 0; i < graph[k].size(); ++i)
        {
            int cost = graph[k][i].cost;
            int to = graph[k][i].to;
            if(is_s[to] == false && distTo[to] > distTo[k] + cost)
            {
                distTo[to] = distTo[k] + cost;
                prenode[to] = k;
            }
        }
    }
}
*/

路径还原

以下两端程序均基于pre数组所有元素被初始化为-1

1.递归实现

int path[Max_V]; //用来存储最短路径

你可能感兴趣的:(【板子】最短路算法)