Dijkstra堆优化(pbds版本priority_queue)

背景

防止赛场上面被卡SPFA,且效率更高更稳定

测试

测试了STL的,和pbds的优先队列,在Dijkstra堆优化中谁更快

STL,初始堆中只有一个元素(起点):141-252ms
在这里插入图片描述
STL,初始堆中有n个元素:238-384ms
在这里插入图片描述

  • pbds,初始堆中只有一个元素(起点):62-110ms
    在这里插入图片描述
  • pbds,初始堆中有n个元素:75-130ms
    在这里插入图片描述
    手写堆,初始堆中有所有元素:39-69ms

此处手写堆就没有对照实验了,手写堆还是快的离谱hhh

在这里插入图片描述

  • 综上测试,使用pbds里面可修改的优先队列,速度还是比STL里面快的,且初始时,堆中仅有一个起点的时候更快。
  • 但是如果没有修改和合并的情况,一般还是STL里的堆更快

代码实现

pb_ds写法
  • pbds,初始堆中只有一个元素(起点)
#include <bits/stdc++.h>
#include <bits/extc++.h>
#include <unordered_map>
#include <unordered_set>
using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;

#define debug(x) cerr << #x << ": " << x << '\n'
#define bd cerr << "----------------------" << el
#define el '\n'
#define cl putchar('\n')
#define pb push_back
#define eb emplace_back
#define x first
#define y second
#define rep(i, a, b) for (register int i = (a); i <= (b); i++)
#define loop(i, a, b) for (int i = (a); i < (b); i++)
#define dwn(i, a, b) for (int i = (a); i >= (b); i--)
#define ceil(a, b) (a + (b - 1)) / b
#define ms(a, x) memset(a, x, sizeof(a))
#define INF 0x3f3f3f3f
#define db double

typedef long long LL;
typedef long double LD;
typedef pair<int, int> PII;
typedef pair<db, db> PDD;
typedef vector<int> vci;
typedef map<int, int> mii;
typedef mii::iterator mii_it;

const int N = 1e5 + 10, M = 2e6 + 10, E = 1e3 + 10, md = 1e9 + 7;
const double PI = acos(-1), eps = 1e-8;

int T, n, m;
#define param PII, greater<PII>, pairing_heap_tag
__gnu_pbds::priority_queue<param> q;
__gnu_pbds::priority_queue<param>::point_iterator its[N];
int dis[N];
vector<PII> g[N];
inline int read()
{
	int f = 1, d = 0;
	char ch;
	ch = getchar();
	while(ch < '0' || ch > '9')
	{
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9')
		d = (d << 1) + (d << 3) + (ch ^ 48), ch = getchar();
	return d * f;
}


void dijkstra(int sta)
{
    q.clear();
    for (int i = 1; i <= n; i++)
    {
        dis[i] = INF; //堆根据first排序,所以dis要放在前面,id放在后面
        
    }
    its[sta] = q.push({0, sta});
    dis[sta] = 0;
    int u;
#define v first
#define w second
    while (!q.empty())
    {
        u = q.top().second;
        q.pop();
        for (auto e : g[u])
        {
            if (dis[e.v] > dis[u] + e.w)
            {
                dis[e.v] = dis[u] + e.w;
                if(its[e.v]!=NULL)q.modify(its[e.v], {dis[e.v], e.v});
                else {
                    its[e.v] = q.push({dis[e.v], e.v});
                }
            }
        }
    }
#undef v
#undef w
    return;
}

int main()
{
    cin.tie(0);
    cout.tie(0);
    cin.sync_with_stdio(false);
    int s;
    // cin >> n >> m >> s;
    n = read();
    m = read();
    s = read();
    int u, v, w;
    rep(i, 1, m)
    {
        // cin >> u >> v >> w;
        u = read();
        v = read();
        w = read();
        g[u].eb(v, w);
    }
    dijkstra(s);
    rep(i, 1, n) if (dis[i] != INF) cout << dis[i] << ' ';
    else cout << INT_MAX << ' ';
}

STL写法
#include <bits/stdc++.h>
#include <bits/extc++.h>
#include <unordered_map>
#include <unordered_set>
using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;

#define debug(x) cerr << #x << ": " << x << '\n'
#define bd cerr << "----------------------" << el
#define el '\n'
#define cl putchar('\n')
#define pb push_back
#define eb emplace_back
#define x first
#define y second
#define rep(i, a, b) for (register int i = (a); i <= (b); i++)
#define loop(i, a, b) for (int i = (a); i < (b); i++)
#define dwn(i, a, b) for (int i = (a); i >= (b); i--)
#define ceil(a, b) (a + (b - 1)) / b
#define ms(a, x) memset(a, x, sizeof(a))
#define INF 0x3f3f3f3f
#define db double

typedef long long LL;
typedef long double LD;
typedef pair<int, int> PII;
typedef pair<db, db> PDD;
typedef vector<int> vci;
typedef map<int, int> mii;
typedef mii::iterator mii_it;

const int N = 1e5 + 10, M = 2e6 + 10, E = 1e3 + 10, md = 1e9 + 7;
const double PI = acos(-1), eps = 1e-8;

int T, n, m;
std::priority_queue<PII, vector<PII>, greater<PII>> q;
int dis[N];
bool vis[N];
vector<PII> g[N];
inline int read()
{
    int f = 1, d = 0;
    char ch;
    ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
        d = (d << 1) + (d << 3) + (ch ^ 48), ch = getchar();
    return d * f;
}

void dijkstra(int sta)
{

    for (int i = 1; i <= n; i++)
    {
        dis[i] = INF; //堆根据first排序,所以dis要放在前面,id放在后面
        if(i != sta) q.push({INF, i});
        else q.push({0, sta});
    }

    dis[sta] = 0;
    // q.push({0, sta});
    int u;
    while (!q.empty())
    {
        u = q.top().second;
        q.pop();
        if (vis[u])
            continue;
        vis[u] = 1;
        for (auto e : g[u])
        {
            if (dis[e.first] > dis[u] + e.second)
            {
                dis[e.first] = dis[u] + e.second;
                q.push({dis[e.first], e.first});
            }
        }
    }
    return;
}

int main()
{
    cin.tie(0);
    cout.tie(0);
    cin.sync_with_stdio(false);
    int s;
    // cin >> n >> m >> s;
    n = read();
    m = read();
    s = read();
    int u, v, w;
    rep(i, 1, m)
    {
        // cin >> u >> v >> w;
        u = read();
        v = read();
        w = read();
        g[u].eb(v, w);
    }
    dijkstra(s);
    rep(i, 1, n) if (dis[i] != INF) cout << dis[i] << ' ';
    else cout << INT_MAX << ' ';
}
手写堆
  • 手写堆,初始堆内有n个元素

#include<bits/stdc++.h>
using namespace std;
const int mx=1e5+10;
const int mn=1e6+10;
const int Max=0x3f3f3f3f;
struct Graph {
	int to,nex,w;
} e[mn];
int last[mx],tot;
void addedge(int from,int to,int w) {
	e[++tot].to=to;
	e[tot].nex=last[from];
	e[tot].w=w;
	last[from]=tot;
}

int n,m,sta,des,cnt,pos[mx],Hsize,pre[mx];
bool s[mx];

//最小堆 
struct dui{
	int d,id;
	//d代表dis距离 
}Heap[mx];

//Heap[0]是中间变量
//Heap[1]是堆顶 
void swap(int a,int b){
	//pos代表  编号在堆中的位置,Heap代表堆中所储存的信息(距离和编号) 
	Heap[0]=Heap[a];
	Heap[a]=Heap[b];
	Heap[b]=Heap[0];
	//里面储存的其实已经是b的信息了 
	pos[Heap[a].id]=a;
	pos[Heap[b].id]=b;
}

void Up(int i){//上浮 
	while((i != 1) &&( Heap[i].d < Heap[i>>1].d )){
		swap(i,i >> 1);
		i >>= 1;
	}
}

void Delete(){
	swap(1,Hsize);//删除堆顶 
	Hsize--;
	//下沉 
	int Par,Chi;
	for(Par=1;Par << 1 <=Hsize;Par=Chi){
		Chi=Par << 1;
		if(Chi+1<=Hsize&&Heap[Chi].d>Heap[Chi+1].d)Chi++;//选择出来,比较小的那个儿子 
		if(Heap[Par].d<Heap[Chi].d)break;//如果父亲已经比两个儿子都小,则合法,break 
		swap(Par,Chi);//交换二者 
	}
}

void Relax(int u,int v,int w){//放松w边 
	if(w + Heap[pos[u]].d<Heap[pos[v]].d){
		Heap[pos[v]].d=w + Heap[pos[u]].d;
		pre[v]=u;//v的前驱是u 
		Up(pos[v]);//上浮,跟父亲比较 
	}
}

void dijkstra(){
	for(int i=1;i<=n;i++){
		Heap[i].id=pos[i]=i;
		Heap[i].d=Max;//赋最大值 
	}
	Heap[sta].d=0;
	swap(1,sta);//起点弄到堆顶 
	Hsize=n;
	int u,v;
	while(Hsize){
		u=Heap[1].id;
		Delete();
		for(int i=last[u];i;i=e[i].nex){
			v=e[i].to;
			if(pos[v]<=Hsize)Relax(u,v,e[i].w);//放松边 
		}
	}
}

int main() {
	scanf("%d%d%d",&n,&m,&sta);//顶点数 边数 起点 终点 
	for(int i=1; i<=m; i++) {
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		addedge(u,v,w);
//		addedge(v,u,w);
	}
	dijkstra(); 
	for(int i = 1; i <= n; i ++ )
	{
		if(Heap[pos[i]].d != Max) cout << Heap[pos[i]].d << ' ';
		else cout << INT_MAX << ' ';
	}
//	printf("%d\n",Heap[pos[des]].d); 
	//编号为des的信息在堆中并没有被舍弃,只是在Dijkstra中访问不到了 
	
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值