1129.Shortest Path with Alternating Colors
===
###### tags: `Medium`,`BFS`,`Graph`
[1129. Shortest Path with Alternating Colors](https://leetcode.com/problems/shortest-path-with-alternating-colors/)
### 題目描述
You are given an integer `n`, the number of nodes in a directed graph where the nodes are labeled from `0` to `n - 1`. Each edge is red or blue in this graph, and there could be self-edges and parallel edges.
You are given two arrays `redEdges` and `blueEdges` where:
* `redEdges[i]` = `[ai, bi]` indicates that there is a directed red edge from node `ai` to node `bi` in the graph, and
* `blueEdges[j]` = `[uj, vj]` indicates that there is a directed blue edge from node `uj` to node `vj` in the graph.
Return an array `answer` of length `n`, where each `answer[x]` is the length of the shortest path from node `0` to node `x` such that the edge colors alternate along the path, or `-1` if such a path does not exist.
### 範例
**Example 1:**
```
Input: n = 3, redEdges = [[0,1],[1,2]], blueEdges = []
Output: [0,1,-1]
```
**Example 2:**
```
Input: n = 3, redEdges = [[0,1]], blueEdges = [[2,1]]
Output: [0,1,-1]
```
**Constraints**:
* 1 <= `n` <= 100
* 0 <= `redEdges.length`, `blueEdges.length` <= 400
* `redEdges[i].length` == `blueEdges[j].length` == 2
* 0 <= `ai`, `bi`, `uj`, `vj` < `n`
### 解答
#### C++
##### 思路:
1. 從原點0開始走, path中的edge必須紅藍交叉, 找每個node與0的最小距離
2. 用BFS從原點開始走, 初始有選紅or藍edge兩種開始的選項, 故遍歷兩次每個node距離取最小
3. 每個node避免重複走, 紀錄該node是從紅edge或是從藍edge走到
```cpp=
class Solution {
public:
void BFS(bool is_red_edge, vector<int>& res, vector<vector<int>>& red_node_adj, vector<vector<int>>& blue_node_adj)
{
vector<bool> red_visited(res.size(), false);
vector<bool> blue_visited(res.size(), false);
queue<int> q;
q.push(0);
if(is_red_edge)
red_visited[0] = true;
else
blue_visited[0] = true;
int step = 0;
while(q.size())
{
int size = q.size();
while(size--)
{
int node = q.front(); q.pop();
res[node] = res[node]==-1 ? step : min(res[node], step);
if(is_red_edge)
{
for(auto& n : red_node_adj[node])
{
if(red_visited[n])
continue;
red_visited[n] = true;
q.push(n);
}
}
else
{
for(auto& n : blue_node_adj[node])
{
if(blue_visited[n])
continue;
blue_visited[n] = true;
q.push(n);
}
}
}
is_red_edge = !is_red_edge;
step++;
}
}
vector<int> shortestAlternatingPaths(int n, vector<vector<int>>& redEdges, vector<vector<int>>& blueEdges) {
vector<vector<int>> red_node_adj(n);
vector<vector<int>> blue_node_adj(n);
for(auto& v : redEdges)
red_node_adj[v[0]].push_back(v[1]);
for(auto& v : blueEdges)
blue_node_adj[v[0]].push_back(v[1]);
vector<int> res(n, -1);
BFS(true, res, red_node_adj, blue_node_adj);
BFS(false, res, red_node_adj, blue_node_adj);
return res;
}
};
```
Time: $O(2*n+2*e)$ `e`為紅藍edge總數, 每個點最多被拜訪兩次, 每個點最多走紅藍兩次edge
Extra Space: $O(n+e)$ Adjacency list儲存`e`個edge, BFS queue最多儲存`n`個node
> [name=XD] [time= Feb 11, 2023]
##### 思路
1. 紀錄下一個點與其邊的顏色`graph[u] = {v, color}`
2. 用BFS找最短路徑
3. 顏色不同的才可以繼續走
4. 走過的邊把他的`v`改成-1,使其不會被重複使用
```cpp=
enum class Color {kInit, kRed, kBlue};
class Solution {
public:
vector<int> shortestAlternatingPaths(int n, vector<vector<int>>& redEdges, vector<vector<int>>& blueEdges) {
vector<int> ans(n, -1);
vector<vector<pair<int, Color>>> graph(n);
queue<pair<int, Color>> q;
for (auto edge : redEdges) {
int a = edge[0], b = edge[1];
graph[a].push_back({b, Color::kRed});
}
for (auto edge : blueEdges) {
int u = edge[0], v = edge[1];
graph[u].push_back({v, Color::kBlue});
}
q.push({0, Color::kInit});
for (int step = 0; !q.empty(); step++) {
for (int i = q.size(); i > 0; i--) {
auto [u, prevColor] = q.front();
q.pop();
if (ans[u] == -1) ans[u] = step;
for (auto& [v, color] : graph[u]) {
if (v == -1 || color == prevColor) continue;
q.push({v, color});
v = -1;
}
}
}
return ans;
}
};
```
> [name=Yen-Chi Chen][time=Sat, Feb 11, 2023]
#### Javascript
```javascript=
function shortestAlternatingPaths(n, redEdges, blueEdges) {
const graph = new Array(n).fill(0).map(() => []);
for (const [v1, v2] of redEdges) {
graph[v1].push([v2, 'red']);
}
for (const [v1, v2] of blueEdges) {
graph[v1].push([v2, 'blue']);
}
const distances = new Array(n).fill(Infinity);
// vertex可以重複走,但是edge不能重複
const redVisited = new Array(n).fill(false);
const blueVisited = new Array(n).fill(false);
const queue = [[0, null, 0]];
// 做BFS 走不同顏色的路
while (queue.length) {
const [node, color, step] = queue.shift();
if (redVisited[node] && blueVisited[node]) continue;
if (color === 'red') {
if (redVisited[node]) continue;
redVisited[node] = true;
} else {
if (blueVisited[node]) continue;
blueVisited[node] = true;
}
// 更新距離
distances[node] = Math.min(distances[node], step);
for (const [vertex, nextColor] of graph[node]) {
if (color === nextColor) continue; // 相同顏色的路無法走
queue.push([vertex, nextColor, step + 1]);
}
}
// 把無法到達的點設為 -1
for (let i = 0; i < distances.length; i++) {
if (distances[i] === Infinity) distances[i] = -1;
}
return distances;
}
```
> [name=Marsgoat][time=Feb 20, 2023]
### Reference
[回到題目列表](https://hackmd.io/@Marsgoat/leetcode_every_day)