专栏文章

SP23132 题解

SP23132题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mioslv7y
此快照首次捕获于
2025/12/03 00:28
3 个月前
此快照最后确认于
2025/12/03 00:28
3 个月前
查看原文

题目分析

很明显,这是一道单源最短路的题,可以使用 Dijkstra 来做这道题(如果是骗分的也可以试试 Floyd),而且还可以说这就是一道 Dijkstra 的版子。
接下来我将会简单说一下 Dijkstra。

Dijkstra

这个算法可以简单概括为“Dijkstra = BFS + 贪心”,大体步骤如下:
步骤做法具体操作结果
11从起点 ss 出发,用 BFS 扩展它的邻居节点把这些邻居点放到一个集合 AA 中,并记录这些点到 ss 的距离
22选择距离 ss 最近的邻居 vv,继续用 BFS 扩展 vv 的邻居首先在 AA 中找到距离 ss 最小的点 vv,把 vv 的邻居点放到 AA 中;如果 vv 的邻居经过 vv 中转,到 ss 的距离更短,则更新这些邻居到 ss 的距离;最后从集合 AA 中移走 vv,后面不再处理 vv得到了从 ssvv 的最短路径;vv 的邻居更新了到 ss 的距离
33重复步骤 22,直到所有点都扩展到并计算完毕集合 AA 为空。计算出所有点到 ss 的最短距离
按照这个步骤,实现 Dijkstra 其实并不难,现在给出参考实现代码。

实现

暴力做法(O(n2)O(n^2)

CPP
struct edge {
  int v, w;
};

vector<edge> e[MAXN];
int dis[MAXN], vis[MAXN];

void dijkstra(int n, int s) {
  memset(dis, 0x3f, (n + 1) * sizeof(int));
  dis[s] = 0;
  for (int i = 1; i <= n; i++) {
    int u = 0, mind = 0x3f3f3f3f;
    for (int j = 1; j <= n; j++)
      if (!vis[j] && dis[j] < mind) u = j, mind = dis[j];
    vis[u] = true;
    for (auto ed : e[u]) {
      int v = ed.v, w = ed.w;
      if (dis[v] > dis[u] + w) dis[v] = dis[u] + w;
    }
  }
}

优先队列做法(O(mlogm)O(m\log m)

CPP
struct edge {
  int v, w;
};

struct node {
  int dis, u;

  bool operator>(const node& a) const { return dis > a.dis; }
};

vector<edge> e[MAXN];
int dis[MAXN], vis[MAXN];
priority_queue<node, vector<node>, greater<node>> q;

void dijkstra(int n, int s) {
  memset(dis, 0x3f, (n + 1) * sizeof(int));
  memset(vis, 0, (n + 1) * sizeof(int));
  dis[s] = 0;
  q.push({0, s});
  while (!q.empty()) {
    int u = q.top().u;
    q.pop();
    if (vis[u]) continue;
    vis[u] = 1;
    for (auto ed : e[u]) {
      int v = ed.v, w = ed.w;
      if (dis[v] > dis[u] + w) {
        dis[v] = dis[u] + w;
        q.push({dis[v], v});
      }
    }
  }
}
Dijkstra 总体上就这些内容了,那么接下来就可以编码了。

参考代码

CPP
#include<bits/stdc++.h>
#define int long long
#define Rint register int
#define fast_running ios::sync_with_stdio(false),std::cin.tie(nullptr),std::cout.tie(nullptr)
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5 + 5, M = 1e5 + 5;
const int INF = 0x3f3f3f3f;
int m, s, cnt;
int head[N], dist[N], flag[N];
priority_queue<PII, vector<PII>, greater<PII>> q;     //优先队列优化 
struct edge {
	int from, to, next, w;
} e[M << 1];
void addedge(int u, int v, int w) {                   //建图 
	e[++cnt].from = u;
	e[cnt].to = v;
	e[cnt].next = head[u];
	e[cnt].w = w;
	head[u] = cnt;
}
void init() {                                         //初始化 
	for (int i = 0; i < N; i++) {
		head[i] = -1;
		flag[i] = 0;
		dist[i] = INF;
	}
	cnt = 0;
	return;
}
void dijshort(int start) {                            //优先队列优化的 Dijkstra 
	dist[start] = 0;
	q.push({dist[start], start});
	while (!q.empty()) {
		PII tp = q.top();
		q.pop();
		int id_x = tp.second, dist_x = tp.first;
		if (flag[id_x]) continue;
		flag[id_x] = 1;
		for (int i = head[id_x]; i != -1; i = e[i].next) {
			int v = e[i].to;
			if (dist[v] > dist_x + e[i].w) {
				dist[v] = dist_x + e[i].w;
				q.push({dist[v], v});
			}
		}

	}
}
signed main() {
	fast_running;
	cin >> m;
	init();
	for (int i = 1; i <= m; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		addedge(u, v, w);
		addedge(v, u, w);
	}
	cin >> s;
	dijshort(s);
	int T, in;
	cin >> T;
	while (T--) {
		cin >> in;
		if (dist[in] == INF) cout << "NO PATH\n";
		else cout << dist[in] << '\n';
	}

	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...