求最短路——迪杰斯特拉算法的优化

本文详细介绍了迪杰斯特拉算法的基本原理及两种实现方式,包括使用结构体和pair进行节点表示的方法,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

original link - http://acm.zjnu.edu.cn/CLanguage/showproblem?problem_id=1211

题意:

给定M条边,N个点的带权无向图,求1到N的最短路

解析:

先讲一下一般做题时可以用到的优化:

1. 显然,当一个点被visvisvis过(当作最近点后),下一次不会再pushpushpush这个点了,但是不保证之前是否有压入这个点的不良状态。所以被visvisvis过的点直接continuecontinuecontinue可以保证每个点只跑一次。
2. 假设我们只求到一个点的最短路,那么显然,如果当前更新的答案劣于终点的答案,就不用压到队列里面去了。
3. 如果终点作为最近的点时,直接输出答案即可。

迪杰斯特拉模板:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
#define N 100009
using namespace std;
int read(){ int ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
} 
int head[N],now;
struct edge{
	int to,nex,val;
}e[10*N];
void add(int a,int b,int v){
	e[++now].to=b;e[now].nex=head[a];e[now].val=v;head[a]=now; 
	e[++now].to=a;e[now].nex=head[b];e[now].val=v;head[b]=now;
}

int n,m,a,b,v;

struct node{
	int _id,dis;
	node(int _id,int dis):_id(_id),dis(dis){}
	bool operator < (const node &a) const{
		return dis>a.dis;
	}
};
priority_queue<node>Q;
int vis[N];
int dist[N];

int main(){
	memset(head,-1,sizeof(head));now=0;
	memset(dist,0x3f,sizeof(dist));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		a=read();b=read();v=read();add(a,b,v);
	}
	Q.push(node(1,0));
	dist[1]=0;
	while(!Q.empty()){
		int j=Q.top()._id;Q.pop();
		if(vis[j])continue;
		vis[j]=1;
		if(j==n){
            printf("%d\n",dist[n]);
            break;
		}
		for(int i=head[j];i!=-1;i=e[i].nex){
			if(vis[e[i].to])continue;
			if(dist[e[i].to]-e[i].val>dist[j] && dist[n]-e[i].val>dist[j]){
				dist[e[i].to]=e[i].val+dist[j];
				Q.push(node(e[i].to,dist[e[i].to]));
			}
		}
	}
} 

还有一种优化,用pairpairpair代替structstructstruct,因为pairpairpair是自带的东西,比较大小什么的都比自己写的结构体优一点。

因为优先队列按照firstfirstfirst升序排序,所以压进优先队列里面的pairpairpairfirstfirstfirst为距离,secondsecondsecond为点的id

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<vector>
#define N 100009
#define ll long long
#define pill pair<int,int>
#define pb push_back
#define mk make_pair
using namespace std;

ll read(){ ll ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;}


vector<pill> v[N];


priority_queue<pill,vector<pill>,greater<pill> >Q;
int vis[N];
int dist[N];

int main(){
	memset(dist,125,sizeof(dist));
	int n=read(),m=read();
	for(int i=1;i<=m;i++){
		int a=read(),b=read(),c=read();
		v[a].pb(mk(b,c));v[b].pb(mk(a,c));
	}
	Q.push(mk(0,1));dist[1]=0;
	while(!Q.empty()){
		int j=Q.top().second;Q.pop();
		if(vis[j])continue;vis[j]=1;
		for(int i=0;i<v[j].size();i++){
			if(vis[v[j][i].first])continue;
			if(dist[v[j][i].first]>dist[j]+v[j][i].second){
				dist[v[j][i].first]=dist[j]+v[j][i].second;
				Q.push(mk(dist[v[j][i].first],v[j][i].first));
			}
		}
	}
	printf("%d\n",dist[n]);
} 

例题

original link - http://acm.zjnu.edu.cn/CLanguage/showproblem?problem_id=1412)

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<set>
#include<map>
#include<queue>
#define D long long
#define pill pair<int,int>
#define mk make_pair
using namespace std;

vector<pill>V[10009];
priority_queue<pill,vector<pill>,greater<pill> >Q;
int vis[10009],dis[10009];
int n,m;
int main(){
	while(cin>>m>>n){
		while(!Q.empty())Q.pop();
		for(int i=1;i<=n;i++)dis[i]=1e9,vis[i]=0,V[i].clear();
		while(m--){
			int a,b,v;scanf("%d%d%d",&a,&b,&v);
			V[a].push_back(mk(b,v));
			V[b].push_back(mk(a,v));
		}
		dis[1]=0;vis[1]=1;
		Q.push(mk(0,1));
		while(!Q.empty()){
			pill e=Q.top();Q.pop();
			int Id=e.second,val=e.first;
			vis[Id]=1;
			if(Id==n)break;
			for(int i=0;i<V[Id].size();i++){
				int a=V[Id][i].first,b=V[Id][i].second;
				if(vis[a])continue;
				if(dis[Id]<dis[a]-b){
					dis[a]=dis[Id]+b;
					Q.push(mk(dis[a],a));
				}
			}
		}
		printf("%d\n",dis[n]);
	}
}
### Dijkstra算法短路径实现与解释 Dijkstra算法是一种用于解决单源短路径问题的经典算法,适用于重的有向图或无向图中的非负情况[^1]。它能够计算从指定起到其他所有节之间的短距离。 #### 算法核心原理 Dijkstra算法的核心思想基于贪心策略。通过维护一个优先队列来动态更新当前已知的短路径,并逐步扩展至未访问过的节。具体而言,在每次迭代中选取具有小临时距离的顶作为新的中间节,并尝试利用此节进一步优化其余目标节的距离估计值[^2]。 对于每一个被处理过的节v来说, 如果发现经由某连接可以使得通往另一尚未完全确认佳路线的目标w变得更近的话 (即如果dist[v]+cost(v,w)< dist[w]), 那么就应该立即调整后者的新估值并记录下相应的前驱信息以便终回溯整个优行走序列[^3]. 以下是采用Python语言编写的简单版本: ```python import heapq def dijkstra(graph, start): distances = {node: float('infinity') for node in graph} distances[start] = 0 priority_queue = [(0, start)] while priority_queue: current_distance, current_node = heapq.heappop(priority_queue) if current_distance > distances[current_node]: continue for neighbor, weight in graph[current_node].items(): distance = current_distance + weight if distance < distances[neighbor]: distances[neighbor] = distance heapq.heappush(priority_queue, (distance, neighbor)) return distances ``` 在这个例子当中`graph`应该是一个字典形式表示加邻接表结构的数据集; 而函数返回的结果将是另一个映射关系——其中键代表各个可能的目的地名称而对应的数值则给出了相应位置相对于出发地的实际开销总和.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值