最短路之堆优化版的dij算法

模板一(vector)常用:

#include<iostream>
#include<cstring>
#include<queue>

using namespace std;

typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 400010; // 把N改为150010就能ac

//堆优化版的dij算法
ll w[N], a[N];

vector<PII>ed[N];
ll dist[N];
bool st[N];

int n, m;

void dij()
{
	memset(dist, 127, sizeof(dist));
	dist[1] = a[1];
	priority_queue<PII, vector<PII>, greater<PII>>q;
	q.push({dist[1], 1});
	while(q.size()){
		PII k = q.top();
		q.pop();
		ll v = k.second;
		if(st[v]) continue;
		st[v] = 1;
		for(auto it : ed[v])
		{
			if(dist[it.first] > dist[v] + it.second + a[it.first])
			{
			    dist[it.first] = dist[v] + it.second + a[it.first];
				q.push({dist[it.first], it.first});
			}
		}
	}
}
int main()
{
	cin >> n >> m;
//	for(int i = 1; i <= n; i ++) cin >> a[i];//每个点的权值
	for(int i = 1; i <= m; i ++)
	{
		ll u, v, w;
		cin >> u >> v >> w;
		ed[u].push_back({v, w});
		ed[v].push_back({u, w});
	}
	dij();
	for(int i = 2; i <= n; i ++)
	{
		cout << dist[i] << " ";
	}
	cout << endl;
	return 0;
}

模板二(数组模拟链表):

#include<iostream>
#include<cstring>
#include<queue>

using namespace std;

typedef pair<int, int> PII;

const int N = 100010; 

// 稀疏图用邻接表来存
int h[N], e[N], ne[N], idx;
int w[N]; // 用来存权重
int dist[N];
bool st[N]; // 如果为true说明这个点的最短路径已经确定

int n, m;

void add(int x, int y, int c)
{
    // 有重边也不要紧,假设1->2有权重为2和3的边,再遍历到点1的时候2号点的距离会更新两次放入堆中
    // 这样堆中会有很多冗余的点,但是在弹出的时候还是会弹出最小值2+x(x为之前确定的最短路径),
    // 并标记st为true,所以下一次弹出3+x会continue不会向下执行。
    w[idx] = c;
    e[idx] = y;
    ne[idx] = h[x]; 
    h[x] = idx++;
}

int dijkstra()
{
    memset(dist, 0x3f, sizeof(dist));
    dist[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> heap; // 定义一个小根堆
    // 这里heap中为什么要存pair呢,首先小根堆是根据距离来排的,所以有一个变量要是距离,
    // 其次在从堆中拿出来的时候要知道知道这个点是哪个点,不然怎么更新邻接点呢?所以第二个变量要存点。
    heap.push({ 0, 1 }); // 这个顺序不能倒,pair排序时是先根据first,再根据second,
                         // 这里显然要根据距离排序
    while(heap.size())
    {
        PII k = heap.top(); // 取不在集合S中距离最短的点
        heap.pop();
        int ver = k.second, distance = k.first;

        if(st[ver]) continue;
        st[ver] = true;

        for(int i = h[ver]; i != -1; i = ne[i])
        {
            int j = e[i]; // i只是个下标,e中在存的是i这个下标对应的点。
            if(dist[j] > distance + w[i])
            {
                dist[j] = distance + w[i];
                heap.push({ dist[j], j });
            }
        }
    }
    if(dist[n] == 0x3f3f3f3f) return -1;
    else return dist[n];
}

int main()
{
    memset(h, -1, sizeof(h));
    scanf("%d%d", &n, &m);

    while (m--)
    {
        int x, y, c;
        scanf("%d%d%d", &x, &y, &c);
        add(x, y, c);
    }

    cout << dijkstra() << endl;

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值