88888888y

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
统计
 

题目:https://www.luogu.com.cn/problem/P3371

题目思路:很明显的最短路模板问题,而本次我们将用迪杰斯特拉算法解决

迪杰斯特拉算法,首先给定一个起点,以这个起点开始,层层推进,一直推到终点

举个例子

比如下面这一个有向连通图

在这张图中,1号点为起点,每根棕色的边都是由小序号通向大序号的一条有向边,上面的数字代表该边的权值

五边形内存储的是当前从起点到这个点的最短路径,绿色的图案代表这个点已经搜索完毕

首先,起点到起点肯定是个0,而起点1号到达与之所连接的2,3,4号的当前最短路径就是与之连接的边的权值

对嘛,刚开始搜你还要什么自行车嘛,而且1号也就这么整完了就够了,如下

现在,1号已经整明白了,现在到2号的最短路径是4,到3是9,到4是6

本着贪心的原则,我们总是认为越小的开始越有可能找到正确答案

所以将二号当做下一个中间点,继续向下,2号的连接点只有4号

BUT! 从2号到4号走 1-->2-->4 的路径要15个权值,但我们刚刚算着,从起点花6个权值可以直达4号

所以到4号的最短路径不变,还是6,如下

现在,2号点结束,3号是9,4号是6,4号将作为下一个中间点继续向下,易得

现在到3是9,到5是17,到6是20,从3再来一遍

等等,3好像没有向外连接任何东西啊

咳咳。。。。。。虽然没有,但依照国际惯例还要再搜一搜

让程序知道它没有,如下

现在到5是17,到6是20,从5开始,发现5只能连着6,而且顺着5走到6还要多花4个权值

那就不用更新了,直接划掉就好。

最后再依照“国际惯例”跟6知会一声,就过了,成品如下

最后,结果出来了

起点1到

1的最短路径是0

2是4

3是9

4是6

5是17

6是20

至此

接下来便是程序实现

由于用二维数组存储有向边的方式时间复杂度为O(n*n)

所以这里直接上(nlogn)的,更简便的堆优化系列迪杰斯特拉

 

#include<bits/stdc++.h>
using namespace std;
#define inf 2147483647
//题目已经变相要求了最大值:2^31-1 
struct hdb{
	int u,v,w,next;
}e[500001];
//在此有向边中,u为起点,v为终点,w为权值 
int h[10001],vi[10001],m,n,s,u,v,w,dis[10001],cnt=0;
//h[i]为顶点i所连接的,输入最晚的一条边
//vi判断这个顶点有没有被访问过 
//dis[i]代表从起点到这个点i的当前最短路径 
struct node{
    int w,now;
    //w为当前路径,now为起点 
    inline bool operator <(const node &x)const{
        return w>x.w;
    }
    //重置运算符,告知优先队列的排法,背过 
};
priority_queue<node> q;
//优先队列,自动排序,格式背过 
void add(int u,int v,int w){
	++cnt;//新开一个 
    e[cnt].u=u;//u为起点 
    e[cnt].v=v;//v为终点 
    e[cnt].w=w;//w为权值 
    e[cnt].next=h[u];
    //将上一条以其作为起点的边放入 
    h[u]=cnt;
    //再把当前这条晚边放入 
}
void dijkstra(){
	for(int i=1;i<=n;++i){
		dis[i]=inf;//初始化 
	}
	dis[s]=0;//起点到起点的距离是0 
	q.push((node){0,s});//存入 
	while(!q.empty()){//还有没搜过的点 
		node p=q.top();
		//顶端权值最小的导出来 
		q.pop();
		u=p.now;//起点导出来 
		if(vi[u]==1){
			continue;
		}//如果被访问过就跳过 
		vi[u]=1;//如果没有就设定为被访问 
		for(int i=h[u];i;i=e[i].next){
			//从最后一条晚边逐一向上搜索 
			int v=e[i].v;//取终点 
			if(dis[v]>dis[u]+e[i].w){
				//如果绕路走比直达所需权值要少 
				dis[v]=dis[u]+e[i].w;
				//更新 
				q.push((node){dis[v],v});
				//插入这个终点作为以后的新起点 
			}
		}
	}
}
int main(){
	scanf("%d%d%d",&n,&m,&s);
	//输入 
	for(int i=1;i<=m;++i){
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
		//输入并加入 
	}
	memset(vi,0,sizeof(vi));
	//归零 
	dijkstra();
	for(int i=1;i<=n;++i){
		printf("%d ",dis[i]);
	}//输出 
	return 0;
}

 

posted on   88888888y  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
 
点击右上角即可分享
微信分享提示