【每日一题】codeforces 20C(1900)(最短路之Dijkstra算法)

想她一次就背十个单词,当我英语过六级后,我就去告诉她,我很在意她
每日一题,坚持使我快乐


今日份快乐:codeforces 20C 传送门
明天份快乐:codeforces 577B 传送门


题目大意

给出一个无向图,有 n 个节点,m 条边,第 i 条边的长度为wi
问:从 1 到 n 号的最短距离

分析

这是一个赤裸裸的最短路的题,题目所有的权值为正,最先考虑 Dijkstra算法。但这个题的数据范围比较大,会出现内存超限,要稍微修改一下,细节看代码 (小声逼逼:这个题用 SPFA算法(我们中国教授提出的算法)也可以解决。不过我感觉这个算法解决有向图的问题会更合适,这里就不讲这个算法了,主要是代码量太大,手懒)。

Dijkstra算法
Dijkstra算法的核心思想是贪心策论下的搜索,不断找寻和修改最短距离
Dijkstra算法可以解决从起点S到其他任意点的最短距离的问题
Dijkstra算法不适用存在负权边的图
Dijkstra算法的讲解:传送门

代码

	
#include <bits/stdc++.h>
#include <vector>
#include <queue>
#define ll long long
using namespace std;	
	
const ll INF = 1e16;
 const int maxn = 1e5+5;

typedef struct Node{ 
	int v;		// 点	 
	ll w;		// 权值 
}node;

bool operator < (const node &a, const node &b){     // 重载 < ,使优先队列按照权值排序 
	return a.w > b.w;
}  
	
vector<node>mp[maxn];	// 邻图表 
ll dis[maxn];		// 1 到 i号点的最短距离 
int path[maxn] = {0};	// 路径,x点是从path[x]到达的
	
void Pr(int x){       		   // 递归路径 
	if(x == 1){		   // x = 1 时就结束 
		cout << 1 << " ";
		return;
	}
		
	Pr(path[x]);		   // 递推前一个点 
	cout << x << " ";
		
}
	
int main(){

	ios::sync_with_stdio(false);    // 关闭输入流可以在这个输入很多的时候可以减少大量时间 
		
	int n, m;
	cin >> n >> m;
		
	int a, b, w;
	node c;
	for(int i = 1; i <= m; i++){    // 邻图表,存边和边的长度 
		cin >> a >> b >> w;
		c.v = b; c.w = w;
		mp[a].push_back(c);
		c.v = a; c.w = w;
		mp[b].push_back(c);
	}
		
	for(int i = 1; i < maxn; i++) dis[i] = INF;  //初始化最大值 
		
	priority_queue<node>qu;          // 算法的核心:优先队列(贪心的实现)
	node now, next;			 // 队列中的 w 是指 1 号点到 v 号点的距离(队列最前端的就是最短距离)
	now.v = 1; now.w = 0;
	qu.push(now);                    // 插入 1 号点 
		
	while(!qu.empty()){				// 当不能再插入的时候就结束 
		now = qu.top();
		qu.pop();
			
		int len = mp[now.v].size();
		for(int i = 0; i < len; i++){            // 遍历当前点可以到达的下一个点 
			next.v = mp[now.v][i].v;
			next.w = now.w + mp[now.v][i].w; 
			if(next.w < dis[next.v]){     	        // 如果当前距离小于储存的最短距离时 
				path[next.v] = now.v;		// 更新路径 
				dis[next.v] = next.w;		// 更新最短距离 
			}
				qu.push(next);			// 下一个点入列 
		}
			
			mp[now.v].clear();			// 这个点已经走过了,储存的点清空,在进入这个点的时候就不用再次循环,当这样可以省去一个标记数组
	}
		
	if(path[n] == 0) cout << -1 << endl;    // 没有可以到达 n 的点 
	else Pr(n);				// 递归路径 
		
	return 0;
}
	

坚持的时候很狼狈,等成功以后,丑的还是丑的🤭

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值