【LeetCode】743. Network Delay Time(C++)

地址:https://leetcode.com/problems/network-delay-time

题目:

There are N network nodes, labelled 1 to N.

Given times, a list of travel times as directed edges times[i] = (u, v, w), where u is the source node, v is the target node, and w is the time it takes for a signal to travel from source to target.

Now, we send a signal from a certain node K. How long will it take for all nodes to receive the signal? If it is impossible, return -1.

Note:

  • N will be in the range [1, 100].
  • K will be in the range [1, N].
  • The length of times will be in the range [1, 6000].
  • All edges times[i] = (u, v, w) will have 1 <= u, v <= N and 1 <= w <= 100.

理解:

单源最短路径问题。想到的就是课本上讲的Dijkstra算法。这篇文章写的比较清楚,不记得的话可以参考一下。https://www.cnblogs.com/skywang12345/p/3711514.html
周六早起+没午觉+上网球课的我,晚上脑子就和炸了一样。并没有看懂这个题给的times是什么玩意,想了半天才明白,给的是每条边的起点、终点和权值。
呵呵,然后Dijkstra算法怎么实现还是不会。。。首先要把给的输入转成矩阵形式,然后再进行比较更方便。但是不知道怎么实现啊。。。嗯。。去看看别人怎么写的,发现很多人都用了priority_queue。。更懵逼了,还是先搞定最基础的 O ( N 2 ) O(N^2) O(N2)的算法吧。

实现1:

首先给个王道书里的方法
closed[]:已经找到了到其他点的最短路径
Min[]:当前的到所有点的最短路径
注意外循环共N次,每次先找到未加入集合的最小距离的点,然后从该点出发更新dist集合。王道书中给的思路是N-1次循环,这种情况下初始的dist就应该是K到其他点的距离,而不是INT_MAX。

class Solution {
public:
	int networkDelayTime(vector<vector<int>>& times, int N, int K) {
		int res = 0;
		vector<vector<int>> adjacency(N + 1, vector<int>(N + 1, -1));
		for (auto edge : times)
			adjacency[edge[0]][edge[1]] = edge[2];
		vector<int> dist(N + 1, INT_MAX);
		dist[K] = 0;
		vector<bool> closed(N + 1,false);
		for (int i = 1; i<=N; ++i) {
			int k = -1;
			for (int j = 1; j<=N; ++j)
				//find the smallest distance in the set of unfounded vertices
				if (!closed[j] && (k == -1 || dist[k]>dist[j]))
					k = j;
			closed[k] = true;
			for (int j = 1; j<=N; ++j)
				if (adjacency[k][j] != -1 && dist[k] + adjacency[k][j]<dist[j])
					dist[j] = adjacency[k][j] + dist[k];
		}
		for (int i = 1; i <= N; ++i) {
			res = max(res, dist[i]);
		}
		return res == INT_MAX ? -1 : res;
	}
};

实现2:

下面这种方法和上面实现略有差别。
这里用queue避免了每次都要通过循环扫描所有的closed,而是把上轮循环更新过距离的节点进行考虑。注意算法里的visited并不是已经寻找到最短路径的点集合,只是防止多次加入队列。这里的队列表示了这一轮更新过距离的节点,因为他们的距离更新了,因此可能导致其他从他们出发的结点距离更新,所以需要加入队列进行下一次的判断。这里的收敛性依靠的是算法自身的性质,而不是程序的判断。当没有结点的距离更新的时候,就停止了。

class Solution {
public:
	int networkDelayTime(vector<vector<int>>& times, int N, int K) {
		int res = 0;
		vector<vector<int>> adjacency(N + 1, vector<int>(N + 1, -1));
		for (auto edge : times)
			adjacency[edge[0]][edge[1]] = edge[2];
		queue<int> q{ {K} };
		vector<int> dist(N + 1, INT_MAX);
		dist[K] = 0;
		while (!q.empty()) {
			//visited here is only for insert v in the queue, which means that dist[v] is updated, maybe some other dist should be update
			unordered_set<int> visited;				
			for (int i = q.size(); i > 0; --i) {
				int u = q.front();
				// printf("%d ", u);
				q.pop();
				for (int v = 1; v <= N; ++v) {
					if (adjacency[u][v] != -1 && (dist[u] + adjacency[u][v] < dist[v])) {
						if (!visited.count(v)) {
							visited.insert(v);
							q.push(v);
						}
						dist[v] = adjacency[u][v] + dist[u];
					}
				}
			}
			// printf("\n");
		}
		for (int i = 1; i <= N; ++i) {
			res = max(res, dist[i]);
		}
		return res == INT_MAX ? -1 : res;
	}
};

实现3:

突然发现基于priority_queue的实现其实和上面差不多,只是priority_queue的top是优先级最高的元素。
来一段别人写好的代码吧。

class Solution {
public:
	int networkDelayTime(vector<vector<int>>& times, int N, int K) {
		// Dijkstra algorithm
		vector<int> distance(N, INT_MAX);
		distance[K - 1] = 0;
		// use an adjacent linked list to represent the graph
		unordered_map<int, unordered_map<int, int>> adj;
		for (auto& e : times) adj[e[0] - 1][e[1] - 1] = e[2];
		// {distance, vertex} as an element added into the priority queue
		// we don't have decrease_key opearation
		auto comp = [](const pair<int, int>& lhs, const pair<int, int>& rhs) {return lhs.first > rhs.first; };
		priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(comp)> q(comp);
		q.push({ 0, K - 1 });
		// when q is not empty
		while (!q.empty())
		{
			auto ele = q.top();
			int src = ele.second;
			q.pop();
			for (auto& edge : adj[src])
			{
				int des = edge.first;
				// relaxation
				if (distance[src] + adj[src][des] < distance[des])
				{
					distance[des] = distance[src] + adj[src][des];
					// if we successfully update the distance, push it into the priority queue
					// for the old value in the priority_queue, it will never successfully update the distance
					// hence, it's okay to have duplicates
					q.push({ distance[des], des });
				}
			}
		}
		// find the maximum time we need to wait, if it's INT_MAX, some nodes must be not reachable
		int ans;
		for (auto& wait : distance) ans = max(ans, wait);
		return ans == INT_MAX ? -1 : ans;
	}
};

实现4:

基于Bellman-Ford算法。
Bellman - ford算法是求含负权图的单源最短路径的一种算法,效率较低,代码难度较小。其原理为连续进行松弛,在每次松弛时把每条边都更新一下,若在n-1次松弛后还能更新,则说明图中有负环,因此无法得出结果,否则就完成。–Bellman-Ford算法

class Solution {
public:
    int networkDelayTime(vector<vector<int>>& times, int N, int K) {
        vector<int> dist(N + 1, INT_MAX);
        dist[K] = 0;
        for (int i = 0; i < N; i++) {
            for (vector<int> e : times) {
                int u = e[0], v = e[1], w = e[2];
                if (dist[u] != INT_MAX && dist[v] > dist[u] + w) {
                    dist[v] = dist[u] + w;
                }
            }
        }

        int maxwait = 0;
        for (int i = 1; i <= N; i++)
            maxwait = max(maxwait, dist[i]);
        return maxwait == INT_MAX ? -1 : maxwait;
    }
};

感觉。。都差不多啊。。
不太舒服。。不会又要感冒吧
这道题应该是目前为止,easy里花时间最多的了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值