Dijkstra算法+堆优化【模板】

Dijkstra算法用于求解一个点到所有点的距离

例子

5 5 1(5个点 5条边 起点为1号节点)
1 2 20(下面5行是5条边的起点、终点与权值)
2 3 30
3 4 20
4 5 20
1 5 100

代码

//原版Dijkstra
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
int edges[10002][10002];
int dist[10002];
int visited[10002];
#define inf 0x3f3f3f3f
int n, m, s;
void Dijkstra()
{
    fill(dist, dist + n+1, inf);//dist数组初始化为inf
    dist[s] = 0;//将起点的dist设为0
    for (int i = 1; i <= n; i++)//因为从起点开始,所以执行n次
    {
        int u = -1, min = inf;
        for (int j = 1; j <= n; j++)//寻找最短边
        {
            if (!visited[j] && dist[j] < min)
            {
                u = j; min = dist[j];
            }
        }
        if (u == -1)return;
        visited[u] = 1;//这里不能忘记
        for (int j = 1; j <= n; j++)
        {
            if (!visited[j])
            {
                if (min + edges[u][j] < dist[j])
                    dist[j] = min + edges[u][j];
            }
        }
    }

}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    cin >> n >> m >> s;
    fill(edges[0], edges[0] + 10002 * 10002, inf);//这种写法在数据量比较大的题目中是会爆内存的
    for (int i = 1; i <= m; i++)
    {
        int a, b,c;
        cin >> a >> b >> c;
        edges[a][b] = c;
    }
    Dijkstra();
    for (int i = 1; i <= n; i++)
        printf("%s%d", i == 1 ? "" : " ", dist[i]);
}

防止爆内存Dijkstra

题目:https://www.luogu.com.cn/problem/P3371

本题目数据量

 

 

 但是还是TLE………………

于是使用vector储存图,详见代码

代码

//改进vector版Dijkstra
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef pair<int, int> p;
//这里最好使用typedef 定义一下下面再用,如果直接vector<pair<int,int>> edges[10002];在OJ编程通不过…………
//priority_queue<pair<int, int> > qq; 
// 注意在两个尖括号之间一定要留 空格,防止误判



vector<p> edges[10002];
long long dist[10002];
int visited[10002];
#define inf 0x3f3f3f3f
int n, m, s;
void Dijkstra()
{
    fill(dist, dist + n+1, inf);
    dist[s] = 0;
    for (int i = 1; i <= n; i++)
    {
        int u = -1;
        long long min = inf;
        for (int j = 1; j <= n; j++)
        {
            if (!visited[j] && dist[j] < min)
            {
                u = j; min = dist[j];
            }
        }
        if (u == -1)return;
        visited[u] = 1;
        for (int j = 0; j <edges[u].size(); j++)//在以u为起点的所有边中寻找
        {
            int vv = edges[u][j].first;//是这条边的终点
            if (!visited[vv])
            {
                if (min + edges[u][j].second< dist[vv])
                    dist[vv] = min + edges[u][j].second;
            }
        }
    }

}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    cin >> n >> m >> s;
    for (int i = 1; i <= m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        edges[a].push_back(make_pair(b, c));//使用每条边的起始节点作为edges的index,pair里是终点与权值
    }
    Dijkstra();
    bool space = false;
    for (int i = 1; i <= n; i++)
    {
        if (visited[i])
            printf("%s%d",space==false?"":" ", dist[i]);
        else printf("%s%s", space == false ? "" : " ", "2147483647");
        space = true;
    }
}
//测试实例
//5 15 5
//2 2 270
//1 4 89
//2 1 3
//5 5 261
//5 2 163
//5 5 275
//4 5 108
//4 4 231
//3 4 213
//3 3 119
//3 1 77
//3 1 6
//2 4 83
//5 5 196
//5 5 94

//166 163 2147483647 246 0

 

Dijkstra堆优化

题目:https://www.luogu.com.cn/problem/P4779

#include<iostream>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
#define maxn 100010
#define maxm 500010
#define inf 0x7fffffff
struct edge
{
    int to;//终点
    int dis;//权值
    int next;//下一条边
    //不添加from起点,意义不大
};
struct node
{
    int dis;//权值
    int pos;//下标
    bool operator <(const node &x)const
    {
        return x.dis < dis;//从小到大排序
    }
};
edge e[maxm];
int head[maxn], dist[maxn], cnt, visited[maxn];
int n, m, s; 
priority_queue<node>q;//每次出队的都是dis最小的,节省了(更新后再比,出现更小的再更新此类情况)消耗的时间 
void addedge(int u, int v, int w)
{
    cnt++;
    e[cnt].dis = w;
    e[cnt].to = v;
    e[cnt].next = head[u];//head[u]总是临时存放着同起点的前一条边,当同起点的后一条边输入时,把前一条边的index赋值给这条边的next(于是同起点的边顺序是输入顺序的反序)
    head[u] = cnt;
}
void Dijkstra()
{
    fill(dist, dist + n + 1, inf);    
    dist[s] = 0;
    q.push({ 0, s });//加入起点
    while (!q.empty())
    {
        node tmp = q.top();
        q.pop();
        int x = tmp.pos, d = tmp.dis;
        if (visited[x])continue;
        visited[x] = 1;//相当于前面的visited[u] = 1;
        for (int i = head[x]; i; i = e[i].next)
        {
            int y = e[i].to;
            if (dist[y] > dist[x] + e[i].dis)
            {
                dist[y] = dist[x] + e[i].dis;
                    q.push({ dist[y], y });
            }
        }
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    cin >> n >> m >> s;
    for (int i = 1; i <= m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        addedge(a, b, c);
    }
    Dijkstra();
    for (int i = 1; i <= n; i++)
        printf("%s%d", i == 1 ? "" : " ", dist[i]);
}

 

posted @ 2020-05-13 10:34  Jason66661010  阅读(1323)  评论(0编辑  收藏  举报