迪杰特斯拉,优先队列
总结:
1.图论之一:迪杰特斯拉算法—联想(结构体edge, 结构体node,访问点标记vis,最短距离arr数组).
贪心策略:先贪目前的最短的路径,确定下一个点的最短距离,然后再从目前的确定的路径中选出最短路径,依次这样
所以用到优先队列.
2. 优先队列(priotity_queue),队头top(), 默认排序从大到小. 参考内容
普通队列(queue) 队头front(). 根据先后进队顺序排放。
3.结构体内比较在优先队列内比较恰恰相反。
单源点最短路径想法,原理:参考博客
从出发点开始,与出发点直接相连的顶点进入优先队列,自动从小到大排序。模板链接.
来道题:AtCoder Beginner Contest 192 E题 train
题意: n点(n个城市),m条双向边(道路),x出发点,y终点,
一座城市到另一座城市,火车发车时间都有间断的,在s*ki(s=0,1,2,3,4…)的时刻发车到下一个城市.车程时间ti。
问从x城市出发,到达y城市需要的最小时间是多少。
思路:显然是迪杰特斯拉算法,只不过到了一座城市多了等待火车发车的时间,
从城市出发时间是ki的整数倍:ll ans=(arr[u]+e[u][i].K-1)/e[u][i].K*e[u][i].K+e[u][i].time; 如果ans<arr[v] 到达该城市的时间刷新。
代码如下:
#include<iostream>
#include<algorithm>
#include<math.h>
#include<cstring>
#include<vector>
#include<queue>
#define ll long long
const int N=2e5+10;
const ll mod=1e9+7;
ll read(){
ll s = 0, f = 1; char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') f = -1;
ch = getchar();
}
while(isdigit(ch)) s = (s << 3) + (s << 1) + (ch ^ 48), ch = getchar();
return s * f;
}
using namespace std;
struct edge{
int u,v; // 始点,终点
ll time,K; //路程上花费的时间 火车发车的时刻
edge(int u,int v,ll time, ll K){
this->u=u;
this->v=v;
this->time=time;
this->K=K;
}
};
struct node{
int u;
ll time; //出发点到u的最短距离
bool operator <(const node &a) const{
//排序规则:从大到小排 ,但在优先队列:相反
return time>a.time;
}
node(int u,ll time){
this->u=u;
this->time=time;
}
};
vector<edge> e[N];
bool vis[N]; //点的访问标记
ll arr[N]; //存储到i最短时间
ll dj(int n,int x,int y){
//初始化
for(int i=1;i<=n;i++){
arr[i]=-1; ///注意这里我是-1,也可以是mod或者INF
vis[i]=false;
}
arr[x]=0;
priority_queue<node> q;
node t(x,0);
q.push(t);
while(!q.empty()){
//队头-------对尾
t=q.top(); //调出队头
q.pop();
int u=t.u;
if(vis[u]) continue;
vis[u]=true;
for(int i=0;i<e[u].size();i++){
int v=e[u][i].v;
if(vis[v]) continue;// v已经是最短, 不需要再判了.
ll ans=(arr[u]+e[u][i].K-1)/e[u][i].K*e[u][i].K+e[u][i].time;
if(ans<arr[v]||arr[v]==-1){
arr[v]=ans;
q.push(node(v,ans));
}
}
}
return arr[y];
}
int main (){
int n,m,x,y;
n=read();
m=read(); x=read(); y=read();
int u,v,time,k;
for(int i=1;i<=m;i++){
u=read();v=read();
time=read();
k=read();
e[u].push_back(edge(u,v,time,k));
e[v].push_back(edge(v,u,time,k));
}
cout<<dj(n,x,y)<<endl;
return 0;
}
优先队列与普通队列的异同:
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
struct node{
int dis,t;
// bool operator <()
};
struct e
{
int r;
bool operator <(const e &a)const{
return r> a.r; //从小到大排序
}
}a[20];
int main (){
priority_queue<e> q;
queue<e> u;
a[1].r=6;
a[2].r=7;
a[3].r=4;
a[4].r=3;
a[5].r=9;
a[6].r=1;
q.push(a[1]); u.push(a[1]);
q.push(a[2]); u.push(a[2]);
q.push(a[3]); u.push(a[3]);
q.push(a[4]); u.push(a[4]);
q.push(a[5]); u.push(a[5]);
q.push(a[6]); u.push(a[6]);
cout<<"优先队列q:";
while(!q.empty()){
cout<<q.top().r<<" ";
q.pop();
}
cout<<endl;
cout<<"普通队列u:";
while(!u.empty()){
cout<<u.front().r<<" ";
u.pop();
}
cout<<endl<<"sort的排序:";
sort(a+1,a+6+1);
for(int i=1;i<=6;i++)
cout<<a[i].r;
}