最短路模板——Dijkstra+堆优化(高级版)

时间复杂度对比:
Dijkstra: O ( n 2 ) O(n^2) O(n2)
Dijkstra + 优先队列(堆优化): O ( 2 ∗ E + V ∗ l o g V ) O(2*E+V*logV) O(2E+VlogV)
SPFA: O ( k ∗ E ) O(k*E) O(kE) k k k为每个节点进入队列的次数,一般小于等于 2 2 2,最坏情况为 O ( V ∗ E ) O(V*E) O(VE)
BellmanFord: O ( V ∗ E ) O(V*E) O(VE),可检测负圈
Floyd: O ( n 3 ) O(n^3) O(n3),计算每对节点之间的最短路径

结论:

① ① 当权值为非负时,用Dijkstra。
② ② 当权值有负值,且没有负圈,则用SPFA,SPFA能检测负圈,但是不能输出负圈。
③ ③ 当权值有负值,而且可能存在负圈,则用BellmanFord,能够检测并输出负圈。
④ ④ SPFA检测负环:当存在一个点入队大于等于V次时,则有负环。

P S PS PS:优先队列和SPFA都有可能被题目卡数据 . . . . . . ...... ......


Dijkstra:

#include<bits/stdc++.h>
using namespace std;

const int INF = 0x3F3F3F3F;
const int maxn = 1005;
int m, n, st, mp[maxn][maxn];
int dis[maxn], vis[maxn];

void init() {
	for (int i=1; i<=n; i++) {
		for (int j=1; j<=n; j++) {
			if (i == j)	mp[i][j] = 0;
			else mp[i][j] = INF;
		}
		dis[i]=INF;
	}
}

void creatgraph() {
	int t1, t2, t3;
	for (int i=0; i<m; i++) {
		scanf("%d%d%d", &t1, &t2, &t3);	// 两个顶点和权值
		if (mp[t1][t2] > t3)	// 防止重复输入相同节点,但是权值不同
			mp[t1][t2] = t3;
		// mp[t2][t1] = t3;
	}
}

void dijkstra(int st) {
	memset(vis, 0, sizeof(vis));
	for (int i=1; i<=n; i++) dis[i] = mp[st][i];
	vis[st] = 1;
	for (int i=1; i<=n-1; i++) {	// 循环n-1次
		/*找出离起点最近的点*/
		int minn = INF, k = -1;
		for (int j=1; j<=n; j++) {
			if (!vis[j] && dis[j]<minn) {
				minn = dis[j];
				k = j;
			}
		}
		if(k==-1) break;
		vis[k] = 1;
		for (int j=1; j<=n; j++) {	// 松弛操作,找到媒介使得出现新的最短路
			if (!vis[j] && dis[k]+mp[k][j] < dis[j])
				dis[j] = dis[k] + mp[k][j];
		}
	}
}

int main() {
	scanf("%d%d%d", &n, &m, &st);	// n个顶点,m条边
	init();	// 初始化地图
	creatgraph();	// 建图
	dijkstra(st);
	for(int i=1; i<=n; i++) {
		if(i==1) printf("%d", dis[i]);
		else printf(" %d", dis[i]);
	}
}

Dijkstra + 堆优化(优先队列):

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e5 + 10;
const ll inf = (ll)1e16;

int n, m;
bool vis[maxn];
ll dis[maxn];
vector <pii> g[maxn];

struct Node{
	int id; ll d;
	Node() {}
	Node(int id, ll d):id(id),d(d){}
	bool operator < (const Node &A) const {
		return d > A.d;
	}
};

void dijkstra(int st){
	for(int i=1; i<=n; i++){
		vis[i] = 0;
		dis[i] = inf;
	}

	dis[st] = 0;
	priority_queue <Node> Q;
	Q.push(Node(st, 0));
	Node nd;

	while(!Q.empty()){
		nd = Q.top(); Q.pop();
		if(vis[nd.id]) continue;
		vis[nd.id] = true;
		for(int i=0; i<g[nd.id].size(); i++){
			int j = g[nd.id][i].first;
			int k = g[nd.id][i].second;
			if(nd.d + k < dis[j] && !vis[j]){
				dis[j] = nd.d + k;
				Q.push(Node(j, dis[j]));
			}
		}
	}
}

int main(){
	int x, y, z, st, ed, cas = 0;
	scanf("%d", &cas);
	while(cas--){
		scanf("%d%d%d", &n, &m, &st);
		for(int i=1; i<=n; i++) g[i].clear();
		while(m--){
			scanf("%d%d%d", &x, &y, &z);
			g[x].push_back(make_pair(y, z));
			//g[y].push_back(make_pair(x, z));
		}
		dijkstra(st);
		for(int i=1; i<=n; i++)
			printf("%d%s", dis[i], " \n"[i==n]);
	}
}

Dijkstra + 配对堆(高级):

#include<bits/stdc++.h>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
const int mn = 100005;
const int maxn = 200005 ;
const int inf = 2147483647;
typedef __gnu_pbds::priority_queue< pair<int,int> ,\
greater< pair<int,int> >,pairing_heap_tag > heap;
heap::point_iterator id[mn];//记录下每个点的迭代器 
heap q;

inline int read(){
    int x=0;
    char ch=getchar();
    while(ch>'9' || ch<'0') ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}

struct edge{int to, next, dis;};
edge e[maxn * 2];
int head[mn], edge_max;
int n, m, st, dis[mn];

void add(int x, int y, int z){
    e[++edge_max].to=y;
    e[edge_max].dis=z;
    e[edge_max].next=head[x];
    head[x]=edge_max;
}

void dij(int x){
    for(int i=1; i<=n; i++) dis[i] = inf;
    dis[x]=0;
    id[x] = q.push(make_pair(0, x));//每次push会返回新加入点的迭代器 
    while(!q.empty()){
        int now = q.top().second;
        q.pop();
        for(int i=head[now]; i; i=e[i].next){
            if(e[i].dis+dis[now] < dis[e[i].to]){
                dis[e[i].to] = dis[now]+e[i].dis;
                if(id[e[i].to]!=0) //如果在堆中 
                    q.modify(id[e[i].to], make_pair(dis[e[i].to], e[i].to));//修改权值 
                else id[e[i].to] = q.push(make_pair(dis[e[i].to], e[i].to));//加入堆 
            }
        }
    }
}
int main(){
    int x, y, z;
    n=read(), m=read(), st=read();
    for(int i=1; i<=m; i++){
        x=read(), y=read(), z=read();
        add(x, y, z);
    }
    dij(st);
	for(int i=1; i<=n; i++)
		if(i==1) printf("%d", dis[i]);
		else printf(" %d", dis[i]);
}
  • 16
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值