题目来源:https://leetcode-cn.com/problems/chuan-di-xin-xi/
大致题意,有n个点(从0到n-1),然后有若干个消息(可视为节点之间的有向边),判断从0点经过k步到n-1点的路径有几条。中间可以有重复边。
简单思路:
使用dfs。首先根据有向边形成每个点的出边列表,然后通过dfs走k步,判断当前点是否为n-1,若为,则有效路径+1。
public class ParseMsgDFS {
int ways, n, k;
List<List<Integer>> edges;
public int numWays(int n, int[][] relation, int k) {
ways = 0; // 初始化
this.n = n;
this.k = k;
edges = new ArrayList<List<Integer>>();
for (int i = 0; i < n; i++) { // 初始化
edges.add(new ArrayList<Integer>());
}
for (int[] edge : relation) { // 获取出边列表
int src = edge[0];
int des = edge[1];
edges.get(src).add(des);
}
dfs(0, 0);
return ways;
}
public void dfs(int index, int steps) {
if (steps == k) {
if (index == n-1) // k步到达n-1
ways++;
return;
}
List<Integer> des = edges.get(index);
for (int next : des) {
dfs(next, steps+1);
}
}
}
这个方法消耗比较大。
动态规划
使用dp[i][j]表示第i步到达节点j的路径数。
那么可知开始时:
对于一条边[src,dst],第i步如果可以到达src,那么第i+1步就可以到达dst。所以dp[i+1][dst]为所有第i步到达的点中有出边目的点为dst的和。然后有dp方程:
代码如下:
public int numWays(int n, int[][] relation, int k) {
int[][] dp = new int[k+1][n];
dp[0][0] = 1; // 初始化
for (int i = 0; i < k; i++) { // 共k轮
for (int[] edge : relation) { // 第i轮可到达每个点的路径数
int src = edge[0];
int des = edge[1];
dp[i+1][des] += dp[i][src];
}
}
return dp[k][n-1];
}