【递归到动态规划】: 机器人走格子问题

题目

在这里插入图片描述

代码

递归版

public static int ways1(int N, int start, int aim, int K) {
    
    
	//参数无效直接返回0
	if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
    
    
		return -1;
	}
	//总共N个位置,从M点出发,还剩K步,返回最终能到达P的方法数
	return process1(start, K, aim, N);
}

// 机器人当前来到的位置是cur,
// 机器人还有rest步需要去走,
// 最终的目标是aim,
// 有哪些位置?1~N
// 返回:机器人从cur出发,走过rest步之后,最终停在aim的方法数,是多少?
public static int process1(int cur, int rest, int aim, int N) {
    
    
	if (rest == 0) {
    
     // 如果已经不需要走了,走完了!
		return cur == aim ? 1 : 0;
	}
	// (cur, rest)
	if (cur == 1) {
    
     // 1 -> 2
		return process1(2, rest - 1, aim, N);
	}
	// (cur, rest)
	if (cur == N) {
    
     // N-1 <- N
		return process1(N - 1, rest - 1, aim, N);
	}
	// (cur, rest)
	return process1(cur - 1, rest - 1, aim, N) + process1(cur + 1, rest - 1, aim, N);
}

缓存版

暴力递归会多余相同的计算,所以当递归状态相同时候,直接返回缓存值。

public static int ways2(int N, int start, int aim, int K) {
    
    
	if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
    
    
		return -1; 
	}
	int[][] dp = new int[N + 1][K + 1];
	for (int i = 0; i <= N; i++) {
    
    
		for (int j = 0; j <= K; j++) {
    
    
			dp[i][j] = -1;
		}
	}
	// dp就是缓存表
	// dp[cur][rest] == -1 -> process1(cur, rest)之前没算过!
	// dp[cur][rest] != -1 -> process1(cur, rest)之前算过!返回值,dp[cur][rest]
	// N+1 * K+1
	return process2(start, K, aim, N, dp);
}

// cur 范: 1 ~ N
// rest 范:0 ~ K
public static int process2(int cur, int rest, int aim, int N, int[][] dp) {
    
    
	if (dp[cur][rest] != -1) {
    
    
		//之前算过了,直接拿值,不递归!
		return dp[cur][rest];
	}
	// 之前没算过!
	int ans = 0;
	if (rest == 0) {
    
    
		ans = cur == aim ? 1 : 0;
	} else if (cur == 1) {
    
    
		ans = process2(2, rest - 1, aim, N, dp);
	} else if (cur == N) {
    
    
		ans = process2(N - 1, rest - 1, aim, N, dp);
	} else {
    
    
		ans = process2(cur - 1, rest - 1, aim, N, dp) + process2(cur + 1, rest - 1, aim, N, dp);
	}
	dp[cur][rest] = ans;//先加缓存再返回
	return ans;

}

动态规划版

直接舍弃递归,用二维数组代替状态。但是这个二维数组是之前暴力递归推到出来的。

public static int ways3(int N, int start, int aim, int K) {
    
    
	if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
    
    
		return -1;
	}
	int[][] dp = new int[N + 1][K + 1];
	dp[aim][0] = 1;
	for (int rest = 1; rest <= K; rest++) {
    
    
		dp[1][rest] = dp[2][rest - 1];
		for (int cur = 2; cur < N; cur++) {
    
    
			dp[cur][rest] = dp[cur - 1][rest - 1] + dp[cur + 1][rest - 1];
		}
		dp[N][rest] = dp[N - 1][rest - 1];
	}
	return dp[start][K];
}

猜你喜欢

转载自blog.csdn.net/VanGotoBilibili/article/details/115261914