单源点最短路径-迪杰,优先队列

迪杰特斯拉,优先队列

总结
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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

axtices

谢谢您的打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值