输出包括一行四个正整数N(2<=N<=5000)、M(1<=M<=N)、K(1<=K<=5000)、P(1<=P<=N)。
输出一个整数,代表最终走到P的方法数对取模后的值。
5 2 3 3
3
1).2->1,1->2,2->3
2).2->3,3->2,2->3
3).2->3,3->4,4->3
1000 1 1000 1
591137401
注意答案要取模
时间复杂度,空间复杂度
。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] params = br.readLine().split(" ");
int n = Integer.parseInt(params[0]);
int s = Integer.parseInt(params[1]);
int k = Integer.parseInt(params[2]);
int e = Integer.parseInt(params[3]);
System.out.println(recurrent(n, s, k, e));
}
private static int recurrent(int n, int cur, int rest, int end) {
if(rest == 0){
// 没有步数了,如果到达了目的地,就生成了一种走法,否则走法无效
return cur == end? 1: 0;
}else if(cur == 1){
// 到达左边界,只能往右走,步数减1
return recurrent(n, cur + 1, rest - 1, end, memory) % 1000000007;
}else if(cur == n){
// 到达右边界,只能往左走,步数减1
return recurrent(n, cur - 1, rest - 1, end, memory) % 1000000007;
}else{
// 中间位置可以往两边走
return (recurrent(n, cur - 1, rest - 1, end, memory) + recurrent(n, cur + 1, rest - 1, end, memory)) % 1000000007;
}
}
} 这种递归的做法逻辑还是很清晰的,可以大体上视为每一步都有两种选择,一共有k步,时间复杂度就是2k指数级别,当k很大时会产生指数爆炸,从而超时。假设递归函数为f,仅传入两个变化的参数cur和rest(n,start和end是固定的,这里省略),假设n=5,start=2,k=4,我们要求的是f(2,,4),就会得到如下图的展开: import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] params = br.readLine().split(" ");
int n = Integer.parseInt(params[0]);
int s = Integer.parseInt(params[1]);
int k = Integer.parseInt(params[2]);
int e = Integer.parseInt(params[3]);
// 初始状态改为无意义的-1
int[][] memory = new int[k + 1][n + 1];
for(int i = 0; i <= k; i++){
for(int j = 0; j <= n; j++)
memory[i][j] = -1;
}
System.out.println(recurrent(n, s, k, e, memory));
}
private static int recurrent(int n, int cur, int rest, int end, int[][] memory) {
// 有记忆,直接返回
if(memory[rest][cur] != -1) return memory[rest][cur];
if(rest == 0){
// 没有步数了,如果到达了目的地,就生成了一种走法,否则走法无效
memory[rest][cur] = cur == end? 1: 0;
}else if(cur == 1){
// 到达左边界,只能往右走,步数减1
memory[rest][cur] = recurrent(n, cur + 1, rest - 1, end, memory) % 1000000007;
}else if(cur == n){
// 到达右边界,只能往左走,步数减1
memory[rest][cur] = recurrent(n, cur - 1, rest - 1, end, memory) % 1000000007;
}else{
// 中间位置可以往两边走
memory[rest][cur] = (recurrent(n, cur - 1, rest - 1, end, memory) + recurrent(n, cur + 1, rest - 1, end, memory)) % 1000000007;
}
return memory[rest][cur];
}
} 仍然是递归,但由于在递归函数的开头就判断了记忆表中是否有f(cur,rest),所以这棵树被进行了大量的剪枝,其实只是不断在填表而已,表的大小是(k+1)*(n+1),因此时间复杂度为O(k*n),以O(k*n)的空间节省了递归展开的时间。 import scala.io.StdIn
object Main {
def main(args: Array[String]): Unit = {
val in = StdIn
val params = in.readLine().split(" ")
val n = params(0).toInt
val start = params(1).toInt
val k = params(2).toInt
val end = params(3).toInt
val dp = Array.ofDim[Int](k + 1, n + 1)
dp(0)(end) = 1 // 剩下0步,到达了end,根据递归函数,直接出来一种方案
// 填表,注意第一列是废的
for(rest <- 1 to k; cur <- 1 to n){
if(cur == 1)
dp(rest)(cur) = dp(rest - 1)(cur + 1) % 1000000007
else if(cur == n)
dp(rest)(cur) = dp(rest - 1)(cur - 1) % 1000000007
else
dp(rest)(cur) = (dp(rest - 1)(cur - 1) + dp(rest - 1)(cur + 1)) % 1000000007
}
println(dp(k)(start))
}
} import java.util.*;
public class Main {
public static final int mod = 1_000_000_007;
public static int process(int N, int M, int K, int P) {
int[] dp = new int[N + 1];
dp[P] = 1;
for (int k = 1; k <= K; k++) {
int upLeft = dp[1];
for (int i = 1; i <= N; i++) {
int tmp = dp[i];
if (i == 1)
dp[i] = dp[i + 1];
else if (i == N)
dp[i] = upLeft;
else
dp[i] = (upLeft + dp[i + 1]) % mod;
upLeft = tmp;
}
}
return dp[M];
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // (2<=N<=5000)
int M = sc.nextInt();
int K = sc.nextInt(); // (1<=K<=5000)
int P = sc.nextInt();
int res = process(N, M, K, P);
System.out.println(res);
}
} import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int M = sc.nextInt();
int K = sc.nextInt();
int P = sc.nextInt();
System.out.println(search(N, M, K, P));
}
public static int search(int N, int M, int K, int P){
if(N < 2 || K <1 || M < 1 || M > N || P <1 ||P > N){
return 0;
}
int[][] dp = new int[K+1][N+1];
dp[0][P] = 1;
for(int i = 1; i <= K; i++){
for(int j = 1; j <= N; j++){
if(j==1){
dp[i][j] = dp[i-1][2] % (int)(1e9+7);
}else if(j == N){
dp[i][j] = dp[i-1][N-1] % (int)(1e9+7);
}else{
dp[i][j] = (dp[i-1][j-1]+dp[i-1][j+1])%(int)(1e9+7);
}
}
}
return dp[K][M] % (int)(1e9+7);
}
}