leetcode_刷题笔记-LCP 07

LCP 07. 传递信息
小朋友 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 深度优先搜索

把关系看成有向图,每个玩家对应一个节点,每个关系对应一条有向边。
本题等价于在有向图中寻找从节点0到节点n-1长度为k的路径数,同一条路径可以重复经过同一个节点。
从节点0出发做深度优先搜索,每一步记录当前所在节点以及经过的轮数。当经过k轮时,如果位于节点n-1,则将方案数加1.搜索结束后,得到总的方案数。
使用列表存储有向边的关系。

class Solution{
public:
	int numWays(int n, vector<vector<int>> &relation, int k) {
		vector<vector<int>> edges(n);
		for (auto &edge : relation) {
			int src = edge[0], dst = edge[1];
			edges[src].push_back(dst);
		}

		int ways=0;
		function<void(int, int)> dfs = [&] (int index, int steps) {
			if (steps == k) {
				if (index == n-1) {
					++ways;
				}
				return;
			}
			for (int to : edges[index]) {
				dfs(to, steps+1);
			}
		};
		dfs(0, 0);
		return ways;
	}
};

2 广度优先搜索

从节点0出发做广度优先搜索,当遍历到k层时,如果位于节点n-1,则将方案数加1.

class Solution{
public:
	int numWays(int n, vector<vector<int>> &relation, int k) {
		vector<vector<int>> edges(n);
		for (auto &edge: relation) {
			int src = edge[0], dst=edge[1];
			edges[src].push_back(dst);
		}

		int steps=0;
		queue<int> que;
		que.push(0);
		while (! que.empty() && steps<k) {
			steps++;
			int size =que.size();
			for (int i=-; i<size; i++) {
				int index = que.front();
				que.pop();
				for (auto &nextIndex: edges[index]) {
					que.push(nextIndex);
				}
			}
		}
		int ways=0;
		if (steps ==k) {
			while (! que.empty()) {
				if (que.front() == n-1) {
					ways++;
				}
				que.pop();
			}
		}
		return ways;
	}
}

3 动态规划

定义动态规划的状态dp[i][j]为经过i轮传递到编号j的玩家的方案数,其中0≤i≤k, 0≤j<n
由于从编号0的玩家开始传递,当i=0时,一定位于编号0的玩家,不会传递到其他玩家,因此动态规划的边界情况如下:
d p [ 0 ] [ j ] = { 1 , j = 0 0 , j ≠ 0 dp[0][j]=\left\{\begin{array}{l} 1, j=0 \\ 0, j≠0 \end{array}\right. dp[0][j]={1,j=00,j=0

状态转移方程
d p [ i + 1 ] [ d s t ] = ∑ [ s r c , d s t ] ∈ r e l a t i o n d p [ i ] [ s r c ] dp[i+1][dst]=\sum_{[src,dst]∈relation} dp[i][src] dp[i+1][dst]=[src,dst]relationdp[i][src]

int numWays(int n, vector<vector<int>>& relatioin, int k) {
	vector<vector<int>> dp(k+1, vector<int> (n));
	dp[0][0]=1;
	for (int i=0; i<k; i++) {
		for (auto& edge: relation) {
			int src=edge[0], dst=edge[1];
			dp[i+1][dst]+=dp[i][src];
		}
	}
	return dp[k][n-1];
}

空间复杂度O(kn)。i大于0时,dp[i][]的值只和dp[i-1][]的值有关,因此将二维数组变成一维数组,空间复杂度O(n)。

int numWays(int n, vector<vector<int>>& relation, int k) {
	vector<int> dp(n);
	dp[0]=1;
	for (int i=0; i<k; i++) {
		vector<int> next(n);
		for (auto& edge : relation) {
			int src=edge[0], dst=edge[1];
			next[dst]+=dp[src];
		}
		dp=next;
	}
	return dp[n-1];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值