想她一次就背十个单词,当我英语过六级后,我就去告诉她,我很在意她
每日一题,坚持使我快乐
今日份快乐: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;
}
坚持的时候很狼狈,等成功以后,丑的还是丑的🤭