最短路-Dijkstra算法整理

维基说的很全面:https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm

理解:

  先设置访问数组vis[]和距离数组dist[],开始时把源点(source)先加入已访问数组(vis[source]=1),源点到源点的距离数组设为0(dist[source]=0);然后其它点到源点的dist[]为源点到该点的距离。然后找与源点相连的最近的点,并将其加入访问数组,再用这个点利用松弛操作更新其它未访问的点。循环执行顶点数-1次结束。

下面代码假设源点为1,终点为N。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 2000;
int matrix[maxn][maxn];
int vis[maxn], dist[maxn];
int N, M;

void Dijkstra(int source)
{
    memset(vis, 0, sizeof(vis));
    vis[source] = 1;
    for (int i = 1; i <= N; i++) dist[i] = matrix[source][i];

    int cost, k;
    for (int i = 1; i < N; i++)
    {
        cost = INF;
        for (int j = 0; j <= N; j++)
        {
            if (!vis[j] && dist[j]<cost)
            {
                cost = dist[j];
                k = j;
            }
        }

        vis[k] = 1;

        for (int j = 0; j <= N; j++)
        {
            if (!vis[j] && matrix[k][j] != INF&&dist[j]>matrix[k][j] + cost)
            {
                dist[j] = matrix[k][j] + cost;
            }
        }

    }
}

int main()
{
    while (scanf("%d%d", &N, &M))
    {
        for (int i = 0; i <= N; i++)
            for (int j = 0; j <= N; j++)
                if (i == j) matrix[i][j] = 0;
                else matrix[i][j] = INF;

        for (int i = 0; i<M; i++) {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            matrix[u][v] = matrix[v][u] = w;
        }
        Dijkstra(1);
        printf("%d\n", dist[N]);
    }
    return 0;
}

用优先队列和vector:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=2000;
struct Node
{
    int num,dis;//num存储当前节点的编号,dis存储路径长度
    Node(){}
    Node(int a,int b){num=a;dis=b;}
    bool operator < (const Node& rhs)const{
        dis>rhs.dis;
    }
};
priority_queue<Node>que;
vector<vector<Node> >v;
int vis[maxn],dist[maxn];
int N,M;

void Dijkstra(int s)
{
    for (int i=0;i<=N;i++) dist[i]=INF;
    dist[s]=0;
    que.push(Node(s,dist[s]));
    while(!que.empty())
    {
        Node p=que.top();que.pop();
        for (int i=0;i<v[p.num].size();i++)
        {
            Node q;
            q.num=v[p.num][i].num;
            if(dist[q.num]>dist[p.num]+v[p.num][i].dis)
            {
                dist[q.num]=dist[p.num]+v[p.num][i].dis;
                que.push(Node(q.num,dist[q.num]));
            }
        }
    }
}

int main()
{
    scanf("%d%d",&N,&M);
    v.clear();
    v.resize(N+1);
    for (int i=0;i<M;i++)
    {
        int fr,to,w;
        scanf("%d%d%d",&fr,&to,&w);
        v[fr].push_back(Node(to,w));
        v[to].push_back(Node(fr,w));

    }
    Dijkstra(1);
    printf("%d\n",dist[N]);
}

 以hdu1874畅通工程续为例,一个pair较为偷懒的写法:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<queue>
 5 using namespace std;
 6 const int maxn = 1005;
 7 vector<pair<int, int> > E[maxn];
 8 int d[maxn];
 9 int n, m;
10 
11 void Dijkstra(int s)
12 {
13     priority_queue<pair<int, int> >Q;
14     d[s] = 0;
15     Q.push(make_pair(-d[s],s));
16     while (!Q.empty())
17     {
18         int now = Q.top().second; Q.pop();
19         for (int i = 0; i < E[now].size(); i++)
20         {
21             int v = E[now][i].first;
22             if (d[v] > d[now] + E[now][i].second)
23             {
24                 d[v] = d[now] + E[now][i].second;
25                 Q.push(make_pair(-d[v], v));
26             }
27         }
28     }
29 }
30 
31 int main()
32 {
33     while (scanf("%d%d",&n,&m)==2)
34     {
35         for (int i = 0; i < n; i++) E[i].clear();
36         for (int i = 0; i < n; i++) d[i] = 1e9;
37         for (int i = 0; i < m; i++)
38         {
39             int x, y, z;
40             scanf("%d%d%d", &x, &y, &z);
41             E[x].push_back(make_pair(y,z));
42             E[y].push_back(make_pair(x, z));
43         }
44         int s, t;
45         scanf("%d%d", &s, &t);
46         Dijkstra(s);
47         if (d[t] == 1e9)
48             printf("-1\n");
49         else
50             printf("%d\n", d[t]);
51     }
52     return 0;
53 }

 

转载于:https://www.cnblogs.com/zxhyxiao/p/7223886.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值