小朋友 A 在和 ta 的小伙伴们玩传信息游戏,游戏规则如下:
有 n 名玩家,所有玩家编号分别为 0 ~ n - 1,其中小朋友 A 的编号为 0
每个玩家都有固定的若干个可传信息的其他玩家(也可能没有)。传信息的关系是单向的(比如 A 可以向 B 传信息,但 B 不能向 A 传信息)。
每轮信息必须需要传递给另一个人,且信息可重复经过同一个人
给定总玩家数 n,以及按 [玩家编号,对应可传递玩家编号] 关系组成的二维数组 relation。返回信息从小 A (编号 0 ) 经过 k 轮传递到编号为 n-1 的小伙伴处的方案数;若不能到达,返回 0。
示例 1:
输入:n = 5, relation = [[0,2],[2,1],[3,4],[2,3],[1,4],[2,0],[0,4]], k = 3
输出:3
解释:信息从小 A 编号 0 处开始,经 3 轮传递,到达编号 4。共有 3 种方案,分别是 0->2->0->4, 0->2->1->4, 0->2->3->4。
示例 2:
输入:n = 3, relation = [[0,2],[2,1]], k = 2
输出:0
解释:信息不能从小 A 处经过 2 轮传递到编号 2
限制:
- 2 <= n <= 10
- 1 <= k <= 5
- 1 <= relation.length <= 90, 且 relation[i].length == 2
- 0 <= relation[i][0],relation[i][1] < n 且 relation[i][0] != relation[i][1]
遍历问题可以用两种遍历方式实现
深度优先遍历:从起点开始遍历;
1.遍历当前节点 a
2.如果 a 能到达 b, 则开始遍历 b;对于 b, k = k - 1;
3.如果 b 能到达下一个节点,又开始遍历下一个节点; 对于该节点,k 又 在 b 的基础上减一
...
4.直到 k = 0,或者没有下一个节点时,返回上一个层的节点,继续遍历上一层节点
class Solution {
public:
int res = 0;
int target;
void dfs(vector<vector<int>> &graph, int cur, int k) {
if (k == 0)
return;
for (auto to : graph[cur]) {
if (to == target && k == 1) {
res++;
}
dfs(graph, to, k - 1);
}
}
int numWays(int n, vector<vector<int>>& relation, int k) {
vector<vector<int>> graph(n);
for (const auto &edge : relation) {
graph[edge[0]].push_back(edge[1]);
}
target = n - 1;
dfs(graph, 0, k);
return res;
}
};
广度优先遍历:从起点开始遍历
1.遍历起点能到达的所有节点,加到队列中。队列中保存了第一轮能到达的所有节点
2.遍历队列中的所有节点,对于能到达的节点又加入到队列中,同时把第一轮的节点移除。此时队列中保存了所有第二轮能到达的节点。
...
3.一直遍历 k 轮,此时队列中保存的是第 k 轮能到达的所有节点
4.对这些节点进行判断,判断是否等于 n - 1;
int numWays(int n, vector<vector<int>>& relation, int k) {
vector<vector<int>> graph(n);
for (const auto &edge : relation) {
graph[edge[0]].push_back(edge[1]);
}
queue<int>q;
q.push(0);
while (k--) {
int size = q.size();
for (int i = 0; i < size; i++) {
int cur = q.front();
q.pop();
for (auto to : graph[cur]) {
q.push(to);
}
}
}
int res = 0;
while (!q.empty()) {
if (q.front() == n - 1) {
++res;
}
q.pop();
}
return res;
}
该问题可以由小问题的结果推导出大问题的结果,也可以用动态规划实现
dp[i][j] 表示经过 i 轮,能到达节点 j 的方案数量。
int numWays(int n, vector<vector<int>>& relation, int k) {
vector<vector<int>> dp(k + 1, vector<int>(n));
dp[0][0] = 1;
for (int i = 1; i <= k; i++) {
for (const auto &edge : relation) {
dp[i][edge[1]] += dp[i - 1][edge[0]];
}
}
return dp[k][n - 1];
}