[leetcode] The shortest path with alternating colors (bfs, dfs)

In a directed graph, nodes are labeled 0, 1, …, n-1. Every edge in this graph is either red or blue, and has self-loops or parallel edges.

Each [i, j] pair in red_edges represents a red directed edge from node i to node j. Similarly, each [i, j] pair in blue_edges represents a blue directed edge from node i to node j.

Returns an array answer of length n, where answer[X] is the length of the shortest path from node 0 to node X with alternating red and blue edges. If no such path exists, then answer[x] = -1.

Example 1:

Input: n = 3, red_edges = [[0,1],[1,2]], blue_edges = []
Output: [0,1,-1]
Example 2:

Input: n = 3, red_edges = [[0,1]], blue_edges = [[2,1]]
Output: [0,1,-1]
Example 3:

Input: n = 3, red_edges = [[1,0]], blue_edges = [[2,1]]
Output: [0,-1,-1]
Example 4:

Input: n = 3, red_edges = [[0,1]], blue_edges = [[1,2]]
Output: [0,1,2]
Example 5:

Input: n = 3, red_edges = [[0,1],[0,2]], blue_edges = [[1,0]]
Output: [0,1,1]

hint:

1 <= n <= 100
red_edges.length <= 400
blue_edges.length <= 400
red_edges[i].length == blue_edges[i].length == 2
0 <= red_edges[i][j], blue_edges[i][j] < n

Link: https://leetcode-cn.com/problems/shortest-path-with-alternating-colors

Thought analysis:

This is a shortest path problem for directed and unweighted graphs, but this problem adds several new conditions to the template:

  1. There are self-loops and parallel edges.
  2. Distinguish colors and alternate them according to the colors.

If we follow the bfs of the template, we will ensure that we will not repeat the traversal by marking the nodes. But if you follow this approach, the situation of ** self-loop is difficult to deal with. **Because a node may need to be traversed multiple times. For example, from one node to the next node, there is only a blue edge, and the node self-loop has a red edge, and the node needs to go to the red edge. At this time, the node can go to the red edge of the self-loop first and then go to the next node.
So, how to deal with this situation?
We can change the vis of the node to the vis of the edge.
Define bool vis[i][j][k] to indicate whether the edge of color k from i to j has been visited.

So, bfs is easy to write.
The members that define the node are: number id, color c, current path length st.
Every time you go out of the queue, update ans, and then traverse all outgoing nodes of the node, if the color of the edge is different from the color of the node and the edge is not
visited After that, just push the out-degree node into the queue.

class Solution {
public:
    struct node{
        int id, c, st;  //1红 2蓝 3红蓝
    };
    
    int mp[102][102];
    bool vis[102][102][3];	//表示 i->j颜色为k的边 
    
    void bfs(vector<int> &ans, int n, int s, int c)
    {
        node t, tt;
        t.id = s, t.c = c, t.st = 0;
        queue<node> Q;
        Q.push(t);
        while(!Q.empty())
        {
            t = Q.front();
            Q.pop();
            ans[t.id] = min(ans[t.id], t.st);	//能到达一个节点,就是一个最短路 
            int clr = t.c==1?2:1;	//clr表示与当前节点相反的颜色
            for(int i = 0;i < n;i++)
            {
                if(mp[t.id][i] > 0 && mp[t.id][i] != t.c && !vis[t.id][i][clr])	//颜色与当前节点不同,出度边未被遍历过   
                {
                    tt.id = i, tt.st = t.st+1, tt.c = clr;
                    vis[t.id][i][tt.c] = 1;
                    Q.push(tt);
                }
            }
        }
    }

    vector<int> shortestAlternatingPaths(int n, vector<vector<int>>& red_edges, vector<vector<int>>& blue_edges) {
        memset(mp,0,sizeof(mp));
        vector<int> ans(n,0x3f3f3f3f);
        for(int i = 0;i < red_edges.size();i++)
        {
            int x = red_edges[i][0], y = red_edges[i][1];
            mp[x][y] = 1;
        }
        for(int i = 0;i < blue_edges.size();i++)
        {
            int x = blue_edges[i][0], y = blue_edges[i][1];
            if(mp[x][y] == 1)	//存在红蓝平行边,意味着该节点红蓝均通,定义为 3 
            mp[x][y] = 3;
            else mp[x][y] = 2;
        }
        memset(vis,0,sizeof(vis));
        bfs(ans,n,0,1);
        memset(vis,0,sizeof(vis));
        bfs(ans,n,0,2);
        for(int i = 0;i < ans.size();i++)
        if(ans[i] == 0x3f3f3f3f) ans[i] = -1;
        return ans;
    }
};

/*
3
[[0,1],[1,2]]
[]
3
[[0,1]]
[[2,1]]
3
[[1,0]]
[[2,1]]
3
[[0,1]]
[[1,2]]
3
[[0,1],[0,2]]
[[1,0]]
*/

The following is a time-out dfs writing method.

class Solution {
public:
    struct node{
        int to, c;
    };

    vector<node> edge[102];	//建立边邻接表
    bool vis[102][102][3];

    void dfs(vector<int> &ans, int n, int id, int c, int st)
    {
        node t;
        ans[id] = min(ans[id], st);
        int clr = c==1?2:1;
        for(int i = 0;i < edge[id].size();i++)
        {
            t = edge[id][i];
            int to = t.to, clr = t.c;
            if(clr != c && !vis[id][to][clr])
            {
                vis[id][to][clr] = 1;
                dfs(ans,n,to,clr,st+1);
                vis[id][to][clr] = 0;
            }
        }
    }


    vector<int> shortestAlternatingPaths(int n, vector<vector<int>>& red_edges, vector<vector<int>>& blue_edges) {
        vector<int> ans(n,0x3f3f3f3f);
        node t;
        for(int i = 0;i < red_edges.size();i++)
        {
            int x = red_edges[i][0], y = red_edges[i][1];
            t.to = y, t.c = 1;
            edge[x].push_back(t);
        }
        for(int i = 0;i < blue_edges.size();i++)
        {
            int x = blue_edges[i][0], y = blue_edges[i][1];
            t.to = y, t.c = 2;
            edge[x].push_back(t);
        }
        memset(vis,0,sizeof(vis));
        dfs(ans,n,0,1,0);
        memset(vis,0,sizeof(vis));
        dfs(ans,n,0,2,0);
        for(int i = 0;i < n;i++) if(ans[i] == 0x3f3f3f3f) ans[i] = -1;
        return ans;
    }
};

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325583529&siteId=291194637