Dijkstra堆优化算法
朴素的Dijkstra算法复杂度一般为O(n*n)的复杂度,能够解决大部分简单的最短路问题
而Dijkstra堆优化的复杂度为O(n*log n),其之所以能够优化是因为利用优先队列(经重载运算<后),使最小值存储在队列的头部,使每次取出的元素都是队列中最小值
结构体重载运算符
因为优先队列默认是最大堆,即队头元素是队列中的最大值,所以可以通过使用结构体来实现优先队列的最小堆
参考博客:https://blog.csdn.net/catglory/article/details/45584043
使用优先队列时,如果需要对node结点从小到大排序,有两种方法:
1:在结构体外重载结构体小于运算符
bool operator <(const Node& a,const Node& b){
return a.v > b.v;
}
//这里以大于重载小于是因为默认情况下,优先队列是以大的作为队首,这样一反,就可以再默认情况下使得小的作为队首
2:在结构体内重载小于运算符
struct Node{
int u,v;
bool operator < (const Node& t)const{
return v > t.v;
}
};
///为什么这样写我也不知道( ̄▽ ̄)"
当然这道题也用到了vector存储存储结构体变量,(因为对与这道题来说,对每一张机票只是用一次,所以需要遍历,并删除旧的机票那一条航道)
所以删除操作用到了erase()函数,删除的是进入vector的最后一个结点
push_back()函数向vector函数结构体变量中加边
size()函数是返回vector中有多少个元素
题意:
题意很明确,一个最短路问题,对于f个机票,遍历操作,每一次加入一个u->v的距离是0的边(注意是单向边)
还有要注意的是本题中距离初始化的最大值为很大很大!!!开Long Long的那种!!
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<iostream>
typedef long long ll;
const ll INF=1e10+7; ///!!!
const int MAX=151007;
using namespace std;
int n,m,f,s,d;
int a,b,c;
struct node ///实现优先队列
{
int v;
ll c;
node(int _v=0,ll _c=0):v(_v),c(_c) {} ///不能少
bool operator <(const node &other)const ///重载运算符
{
return c>other.c;
}
};
struct _Edge
{
int v;
ll c;
_Edge(int _v=0,ll _c=0):v(_v),c(_c) {}
};
vector<_Edge> edge[MAX]; ///开一个vector类型的结构体二维变量
bool vis[MAX]; ///判断是否便利过
ll dis[MAX]; ///到第i个点的最小值
void addedge(int u,int v,ll w)
{
edge[u].push_back(_Edge(v,w)); ///建边操作,加入到vector中
}
void diji(int s)
{
memset(vis,false,sizeof(vis));
for(int i=0; i<n; i++)
{
dis[i]=INF;
}
priority_queue<node> q; ///优先队列
while(!q.empty()) q.pop(); ///每一次搜索,都需要把原先优先队列中的元素清空
dis[s]=0;
q.push(node(s,0)); ///起点加入队列
while(!q.empty())
{
node h=q.top();
q.pop();
int u=h.v;
if(vis[u]) continue;
vis[u]=true;
for(int i=0; i<edge[u].size(); i++) ///对每一个与u相连的结点遍历
{
int t=edge[u][i].v;
if(!vis[t]&&dis[t]>dis[u]+edge[u][i].c)
{
dis[t]=dis[u]+edge[u][i].c;
q.push(node(t,dis[t])); ///把每一个最小结点加入优先队列中
}
}
}
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&f,&s,&d);
for(int i=0; i<m; i++)
{
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
}
int p,q;
ll ans=INF;
if(f!=0)
{
for(int i=0; i<f; i++)
{
scanf("%d%d",&p,&q);
addedge(p,q,0);
diji(s);
ans=min(ans,dis[d]);
edge[p].erase(edge[p].end()-1); ///删除操作
}
}
else
{
diji(s);
ans=min(ans,dis[d]);
}
printf("%lld\n",ans);
return 0;
}