P4779 【模板】单源最短路径(标准版)
·
P4779 【模板】单源最短路径(标准版) - 洛谷 | 计算机科学教育新生态
题目背景
2018年7月19日,某位同学在NOI Day 1 T1 归程一题里非常熟练地使用了一个广为人知的算法求最短路。
然后呢?
100 → 60:
Ag → Cu:
最终,他因此没能与理想的大学达成约。
小F衷心祝愿大家不再重蹈覆辙。
以下是根据图片内容生成的格式化文档:
题目描述
给定一个n个点,m条有向边的带非负权图,请你计算从s出发,到每个点的距离。
数据保证你能从s出发到任意点。
输入格式
第一行为三个正整数n,m,s。第二行起m行,每行三个非负整数w,vi, wi,表示从uᵢ到vᵢ有一条权值为wᵢ的有向边。
输出格式
输出一行n个空格分隔的非负整数,表示s到每个点的距离。
输入输出样例
输入#1
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
输出#1
0 2 4 3
说明/提示
样例解释请参考数据随机的模板题。
- 1≤n≤1e5
- 1≤m≤2×1e5
- s=1
- 1≤ui,vi≤n
- 0≤wi≤1e9
- 0≤∑wi≤1e9
本题数据可能会持续更新,但不会重测,望周知。
2018.09.04 数据更新 from @zzq
思路:
spfa算法,超时的。
代码如下:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstring>
using namespace std;
typedef long long ll;
const ll N = 2e5 * 5 + 5;
ll tot = 0;
ll n, m, s;
struct Edge{
ll next,to,w;
}e[N];
ll head[N],dis[N];
void add(ll u,ll v,ll w)
{
tot++;
e[tot].next = head[u];
e[tot].to = v;
e[tot].w = w;
head[u] = tot;
}
void spfa()
{
bool vis[N] = {false};
queue<ll> q;
q.push(s);
vis[s] = true;
memset(dis, 0x3f, sizeof(dis));
dis[s] = 0;
while (!q.empty())
{
ll pos = q.front();
q.pop();
vis[pos] = false; // 标记为不在队列中
for (ll u = head[pos]; u != -1; u = e[u].next)
{
ll to = e[u].to;
ll w = e[u].w;
// 先判断能否松弛,不管 to 是否在队列中
if (dis[to] > dis[pos] + w)
{
dis[to] = dis[pos] + w;// 松弛成功后,若 to 不在队列则入队
if (!vis[to])
{
q.push(to);
vis[to] = true;
}
}
}
}
}
int main()
{
cin >> n >> m >> s;
for(ll i = 1 ; i <= n ; i++)
head[i] = -1;
for(ll i = 1 ; i <= m ; i++)
{
ll u,v,w;
cin >> u >> v >> w;
add(u,v,w);
}
spfa();
for(ll i = 1 ; i <= n ; i++)
cout << dis[i] << " ";
return 0;
}
思路如下:
dijstra算法
由于数据超过了1e5,所以用邻接表构图即可。
代码如下:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstring>
using namespace std;
typedef long long ll;
const ll N = 2e5 * 5 + 5;
ll tot = 0;
ll n, m, s;
struct Edge
{
ll next;
ll to;
ll w;
} e[N];
typedef pair<int, int> PII;
ll head[2 * N], dis[2 * N];
bool vis[2 * N];
// 添加边
void add(ll u, ll v, ll w) {
tot++;
e[tot].next = head[u];
e[tot].to = v;
e[tot].w = w;
head[u] = tot;
}
// 初始化
void init() {
memset(dis, 0x3f, sizeof(dis)); // 初始化最短距离为无穷大
memset(head, -1, sizeof(head)); // 初始化图的头指针
memset(vis, false, sizeof(vis)); // 初始化所有节点未访问
}
void dijkstra() {
priority_queue<PII, vector<PII>, greater<PII>> q; // 优先队列,最小堆,对第一个int排序,也就是d
dis[s] = 0;
q.push({0, s});
while (!q.empty()) {
auto k = q.top(); // 取出队首元素
q.pop(); // 出队
ll d = k.first, pos = k.second;
if (vis[pos]) continue; // 如果该节点已经访问过,跳过
vis[pos] = true;
// 遍历该节点的所有邻接边
ll u = head[pos];
while (u != -1) {
ll to = e[u].to; // 邻接点编号
ll w = e[u].w; // 边的权值
if (dis[to] > w + d) { // 如果找到更短的路径
dis[to] = w + d; // 更新最短距离
q.push({dis[to], to});
}
u = e[u].next; // 继续遍历下一个邻接点
}
}
for (int i = 1; i <= n; i++)
{
if (dis[i] == 0x3f3f3f3f3f3f3f3f) //如果数据类型是long long 那么就是0x3f3f3f3f3f3f3f3f,如果是int 那么就是0x3f3f3f3f
cout << "INF" << " ";
else
cout << dis[i] << " ";
}
cout << endl; // 换行
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> s;
init(); // 初始化
for (ll i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
add(u, v, w);
}
dijkstra();
return 0;
}

更多推荐



所有评论(0)