洛谷 P1629 邮递员送信-反向建边

洛谷 P1629 邮递员送信

题目描述:

有一个邮递员要送东西,邮局在节点 11。他总共要送 n-1n−1 样东西,其目的地分别是节点 22 到节点 nn。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 mm 条道路。这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局。求送完这 n-1n−1 样东西并且最终回到邮局最少需要的时间。


思路:

正常跑一遍\(Dijkstra\),之后再反向建边再跑一遍\(Dijkstra\),将两遍的最短路径长度加起来就是答案。

对于反向建边,我的处理方法是用一个类封装链式前向星,每条边正着添加到\(g_1\)中,反着添加到\(g_2\)中。

也有dl用一个链式前向星存正反两个图,在存反向边的时候将每个点都加上\(n\)(点的数量)。


AC代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>

const int Maxn = 100005;
const int INF = 0x3f3f3f3f;

struct Node {
	int pos, dis;

	Node(){}

	Node(int pos, int dis):pos(pos), dis(dis){}

	bool operator < (const Node &x) const {
		return dis > x.dis;
	}
};

class G {
public:
	struct EDGE {
		int v, w, next;
	} e[Maxn];
	
	int head[Maxn], tot;

	G(){tot = 1;}
	
	void add(int u, int v, int w) {
		e[tot].v = v;
		e[tot].w = w;
		e[tot].next = head[u];
		head[u] = tot++;
	}
} g1, g2;

int dis[Maxn], vis[Maxn];

void dijkstra(int s, G g) {
	memset(dis, INF, sizeof dis);
	memset(vis, 0, sizeof vis);
	dis[s] = 0;
	std::priority_queue<Node>q;
	q.push(Node(s, 0));
	for (; !q.empty();) {
		Node f = q.top();
		q.pop();
		if (vis[f.pos]) {
			continue;
		}
		vis[f.pos] = true;
		for (int i = g.head[f.pos]; i; i = g.e[i].next) {
			int v = g.e[i].v;
			int w = g.e[i].w;
			if (dis[v] > dis[f.pos] + w) {
				dis[v] = dis[f.pos] + w;
				q.push(Node(v, dis[v]));
			}
		}
	}
}

void solve() {
	int n, m;
	scanf("%d %d", &n, &m);
	int u, v, w;
	for (int i = 0; i < m; i++) {
		scanf("%d %d %d", &u, &v, &w);
		g1.add(u, v, w);
		g2.add(v, u, w);
	}
	dijkstra(1, g1);
	int ans = 0;
	for (int i = 1; i <= n; i++) {
		ans += dis[i];
	}
	dijkstra(1, g2);
	for (int i = 1; i <= n; i++) {
		ans += dis[i];
	}
	printf("%d\n", ans);
}

int main() {
	solve();
	return 0;
}



posted @ 2021-02-06 17:17  牟翔宇  阅读(130)  评论(0编辑  收藏  举报