1. 程式人生 > >【LeetCode】743. Network Delay Time(C++)

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

題目:

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(N2)O(N^2)的演算法吧。

實現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裡花時間最多的了。