• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
道路与航线 Dijkstra+DAG求最短路

道路与航线

题目

道路与航线

思路

​ 一开始想的是SPFA, 平均情况\(O(M)\), 但是最坏是\(N \times M\), 提交后超时了。开始思考题目中的边和相关条件

1. 道路**无向**,且为**正权边**
1. 航线**有向**,且可能存在**负权边**,另外航线不存在回路,即为$DAG(有向无环图)$

​ 问题是求从源点\(s\)到所有点的距离, 我们考虑将每个城镇(一个岛,内部不存在航线)当作一个连通图,对于连通图内部我们可以采用Dijkstra,对于连通图外部显然我们按从一条线上头到尾的顺序进行更新就是最短路(拓扑序),这样做的复杂度为

\[(m1logn +m2logn + \dots mnlogn) + (V + E) =>O(ElogV) \]

​ 我们可以将源点的距离初始化0, 再Dijkstra内部更新同一连通块的点的同时减少非同一连通块的入度,同时更新拓扑序上的点的最短距离。

Code

#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
#define debug(x) std::cout << x << "\n"
using i64 = long long;

const int N = 3e4, M = 2e5;

int t, r, p, s;

int h[N], ne[M], e[M], w[M], idx;

int dist[N], id[N], en[N], bcnt;

std::vector<int> block[N];

std::queue<int> q1;

bool st[N];

void add(int a, int b, int c) {
	ne[idx] = h[a], h[a] = idx, e[idx] = b, w[idx ++] = c;
}

void dfs(int u, int cnt) {
	block[cnt].push_back(u);
	id[u] = cnt;

	// debug(u);
	
	for (int i = h[u]; ~i; i = ne[i]) {
		int j = e[i];
		if (!id[j]) {
			dfs(j, cnt);
		}
	}
}

void dijkstra(int t) {
	std::priority_queue<std::pair<int, int>> h1;

	for (auto x: block[t]) h1.push({-dist[x], x});

	while (h1.size()) {
		auto t = h1.top(); h1.pop();

		int u = t.second;

		if (st[u]) continue;
		st[u] = true;

		for (int i = h[u]; ~i; i = ne[i]) {
			int j = e[i];

			// 不是一个连通块入度--
			if (id[j] != id[u] && -- en[id[j]] == 0) {
				q1.push(id[j]);
			}

			if (dist[j] > dist[u] + w[i]) {
				// 不管是不是都要更新边权, 应为拓扑序保证了更新结果为最短路
				dist[j] = dist[u] + w[i];

				// 是一个连通块就入堆
				if (id[j] == id[u])
					h1.push({-dist[j], j});
			}
		}
	}
}

void topsort() {
	memset(dist, 0x3f, sizeof dist);

	dist[s] = 0;

	for (int i = 1; i <= bcnt; i ++)
		if (!en[i])
			q1.push(i);	
		
	while (q1.size()) {
		int t = q1.front();
		q1.pop();
		dijkstra(t);
	}
}

int main() {

	std::ios::sync_with_stdio(false);
	
	memset(h, -1, sizeof h);

	std::cin >> t >> r >> p >> s;

	for (int i = 1; i <= r; i ++) {
		int a, b, c;

		std::cin >> a >> b >> c;

		add(a, b, c);
		add(b, a, c);
	}

	for (int i = 1; i <= t; i ++) {
		if (!id[i]) {
			dfs(i, ++ bcnt);
		}
	}

	for (int i = 1; i <= p; i ++) {
		int a, b, c;

		std::cin >> a >> b >> c;

		add(a, b, c);

		en[id[b]] ++;
	}

	topsort();

	for (int i = 1; i <= t; i ++) {
		if (dist[i] >= 0x3f3f3f3f / 2) std::cout << "NO PATH\n";
		else std::cout << dist[i] << "\n";
	}
}
posted on 2023-04-12 19:21  Jack404  阅读(16)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3