KamaCoder 98. 所有可到达路径 + LC 797. All Paths From Source to Target

题目要求

给定一个有 n 个节点的有向无环图,节点编号从 1 到 n。请编写一个函数,找出并返回所有从节点 1 到节点 n 的路径。每条路径应以节点编号的列表形式表示。

输入描述

第一行包含两个整数 N,M,表示图中拥有 N 个节点,M 条边

后续 M 行,每行包含两个整数 s 和 t,表示图中的 s 节点与 t 节点中有一条路径

输出描述

输出所有的可达路径,路径中所有节点之间空格隔开,每条路径独占一行,存在多条路径,路径输出的顺序可任意。如果不存在任何一条路径,则输出 -1。

注意输出的序列中,最后一个节点后面没有空格! 例如正确的答案是 `1 3 5`,而不是 `1 3 5 `, 5后面没有空格!

输入示例

5 5
1 3
3 5
1 2
2 4
4 5

 

输出示例

1 3 5
1 2 4 5

思路 

首先要知道图应该怎么存储,然后是通过搜索的方法找出所有的边。

图的存储
邻接矩阵

本题有n个节点,节点标号从1开始,为了对其标号和下标,我们申请n+1*n+1这么大的二维数组。

vector<vector<int>> graph(n + 1, vector<int>(n + 1, 0));

输入m个边,构造方式如下:

while(m--) {
    cin >> s >> t;
    // 使用邻接矩阵,1表示节点s指向节点t
    graph[s][t] = 1;
}
邻接表

采用数组+链表的形式来表示。

vector<list<int>> graph(n + 1); // 邻接表,list为C++里的链表,初始时没有申请空间,随用随取

// 输入m个边
while(m--) {
    cin >> s >> t;
    // 使用邻接表,表示s —> t是相连的
    graph[s].push_back(t);
}
深度优先搜索

深搜三部曲:1.确认递归函数、参数, 2.确认终止条件,3.处理目前搜索节点出发的路径

1. 确认递归函数、参数

首先dfs函数一定要存一个图,用来遍历,需要存一个目前我们遍历的节点,定义为x。

还需要存储终点位置n,当x==n时表示到达了终点。

至于 单一路径 和 路径集合(答案)可以放在全局变量。

vector<vector<int>> result; // 收集符合条件的路径
vector<int> path; // 0节点到终点的路径
// x:目前遍历的节点
// graph:存当前的图
// n:终点
void dfs (const vector<vector<int>>& graph, int x, int n) {

 2. 确认终止条件

当目前遍历的节点为最后一个节点n的时候,就找到了一条从出发点到终止点的路径。

// 当前遍历的节点x,到达节点n
if (x == n) { // 找到符合条件的一条路径
    result.push_back(path);
    return;
}

3. 处理目前搜索节点出发的路径

接下来时走当前遍历节点x的下一个节点。

// 找到节点x指向哪些节点
for (int i = 1; i <= n; ++i) { // 遍历节点x链接的所有节点
    if (graph[x][i] == 1) { // 找到x指向的节点就是i
        // 将x所指向的节点加入到单一路径中
        path.push_back(i);
        // 进入下一层递归
        dfs(graph, i, n);
        // 回溯过程,撤销本次添加节点的操作
        path.pop_back();
    }
}
打印结果

注意结尾没有空格

// 输出结果
if (result.size() == 0) cout << -1 << endl;
for (const vector<int> &pa : result) {
    for (int i = 0; i < pa.size() - 1; ++i) { // 打印到倒数第二个
        cout << pa[i] << " ";
    }
    cout << pa[pa.size() - 1] << endl;
}

本题代码

C++邻接矩阵写法
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> result;
vector<int> path;

void dfs(const vector<vector<int>>& graph, int x, int n) {
    if (x == n) {
        result.push_back(path);
        return;
    }
    for (int i = 1; i <= n; ++i) {
        if (graph[x][i] == 1) {
            path.push_back(i);
            dfs(graph, i, n);
            path.pop_back();
        }
    }
}

int main() {
    int n, m, s, t;
    cin >> n >> m;
    vector<vector<int>> graph(n + 1, vector<int>(n + 1, 0));
    for (int i = 1; i <= m; ++i) {
        cin >> s >> t;
        graph[s][t] = 1;
    }
    path.push_back(1); // 注意:无论什么路径都是从节点0(1)出发
    dfs(graph, 1, n);
    
    if (result.size() == 0) cout << -1 << endl;
    for (const vector<int> &pa : result) {
        for (int i = 0; i < pa.size() - 1; ++i) {
            cout << pa[i] << " ";
        }
        cout << pa[pa.size() - 1] << endl;
    }
}
C++邻接表写法
#include <iostream>
#include <vector>
#include <list>
using namespace std;
vector<vector<int>> result;
vector<int> path;

void dfs(const vector<list<int>>& graph, int x, int n) {
    if (x == n) {
        result.push_back(path);
        return;
    }
    for (int i : graph[x]) {
        path.push_back(i);
        dfs(graph, i, n);
        path.pop_back();
    }
}

int main() {
    int n, m, s, t;
    cin >> n >> m;
    vector<list<int>> graph(n + 1);
    while (m--) {
        cin >> s >> t;
        graph[s].push_back(t);
    }
    path.push_back(1); // 注意:无论什么路径都是从节点0(1)出发
    dfs(graph, 1, n);
    
    if (result.size() == 0) cout << -1 << endl;
    for (const vector<int> &pa : result) {
        for (int i = 0; i < pa.size() - 1; ++i) {
            cout << pa[i] << " ";
        }
        cout << pa[pa.size() - 1] << endl;
    }
}
Python邻接矩阵写法
def dfs(graph, x, n, path, result):
    if x == n:
        result.append(path.copy())
        return
    for i in range(1, n+1):
        if graph[x][i] == 1:
            path.append(i)
            dfs(graph, i, n, path, result)
            path.pop()
            
def main():
    n, m = map(int, input().split())
    graph = [[0] * (n+1) for _ in range(n+1)]
    
    for _ in range(m):
        s, t = map(int, input().split())
        graph[s][t] = 1
        
    result = []
    dfs(graph, 1, n, [1], result)
    
    if not result:
        print(-1)
    else:
        for path in result:
            print(' '.join(map(str, path)))
            
if __name__ == "__main__":
    main()
Python邻接表写法(注意collections.defaultdict的使用)
from collections import defaultdict

result = []
path = []

def dfs(graph, x, n, path, result):
    if x == n:
        result.append(path.copy())
        return
    for i in graph[x]:
            path.append(i)
            dfs(graph, i, n, path, result)
            path.pop()
            
def main():
    n, m = map(int, input().split())
    graph = defaultdict(list)
    
    for _ in range(m):
        s, t = map(int, input().split())
        graph[s].append(t)
        
    result = []
    dfs(graph, 1, n, [1], result)
    
    if not result:
        print(-1)
    else:
        for pa in result:
            print(' '.join(map(str, pa)))
            
if __name__ == "__main__":
    main()

Leetcode 797. All Paths From Source to Target  

题目也是一道有向无环的图的求所有起点到终点的路径问题,区别在于不需要调整输入输出。(题目中的图已经给出了邻接表的存储形式)

C++
class Solution {
public:
    vector<int> path;
    vector<vector<int>> result;

    void dfs(const vector<vector<int>>& graph, int x, int n) {
        if (x == n) {
            result.push_back(path);
            return;
        }
        for (int i : graph[x]) {
            path.push_back(i);
            dfs(graph, i, n);
            path.pop_back();
        }
    }

    vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
        path.push_back(0);
        dfs(graph, 0, graph.size() - 1);
        return result;    
    }
};
Python (注意列表是引用类型,后续修改会影响已经添加的路径,所以要用.copy())
class Solution:

    def dfs(self, graph, x, n, path, result):
        if (x == n):
            result.append(path.copy())
            return
        for i in graph[x]:
            path.append(i)
            self.dfs(graph, i, n, path, result)
            path.pop()

    def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]:
        path = []
        result = []
        path.append(0)
        self.dfs(graph, 0, len(graph) - 1, path, result)
        return result

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值