package class07;
public classCode01_RobotWalk{
public static int ways1(int N,int M,int K,int P){// 参数无效直接返回0if(N <2|| K <1|| M <1|| M > N || P <1|| P > N){return0;}// 总共N个位置,从M点出发,还剩K步,返回最终能达到P的方法数
return walk(N, M, K, P);}// N : 位置为1~ N,固定参数
// cur : 当前在cur位置,可变参数
// rest : 还剩res步没有走,可变参数
// P : 最终目标位置是P,固定参数
// 该函数的含义:只能在1~N这些位置上移动,当前在cur位置,走完rest步之后,停在P位置的方法数作为返回值返回
public static int walk(int N,int cur,int rest,int P){// 如果没有剩余步数了,当前的cur位置就是最后的位置
// 如果最后的位置停在P上,那么之前做的移动是有效的
// 如果最后的位置没在P上,那么之前做的移动是无效的
if(rest ==0){return cur == P ? 1:0;}// 如果还有rest步要走,而当前的cur位置在1位置上,那么当前这步只能从1走向2// 后续的过程就是,来到2位置上,还剩rest-1步要走
if(cur ==1){return walk(N,2, rest -1, P);}// 如果还有rest步要走,而当前的cur位置在N位置上,那么当前这步只能从N走向N-1// 后续的过程就是,来到N-1位置上,还剩rest-1步要走
if(cur == N){return walk(N, N -1, rest -1, P);}// 如果还有rest步要走,而当前的cur位置在中间位置上,那么当前这步可以走向左,也可以走向右
// 走向左之后,后续的过程就是,来到cur-1位置上,还剩rest-1步要走
// 走向右之后,后续的过程就是,来到cur+1位置上,还剩rest-1步要走
// 走向左、走向右是截然不同的方法,所以总方法数要都算上
return walk(N, cur +1, rest -1, P)+ walk(N, cur -1, rest -1, P);}
public static int ways2(int N,int M,int K,int P){// 参数无效直接返回0if(N <2|| K <1|| M <1|| M > N || P <1|| P > N){return0;}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];}elseif(j == N){
dp[i][j]= dp[i -1][N -1];}else{
dp[i][j]= dp[i -1][j -1]+ dp[i -1][j +1];}}}return dp[K][M];}
public static int ways3(int N,int M,int K,int P){// 参数无效直接返回0if(N <2|| K <1|| M <1|| M > N || P <1|| P > N){return0;}int[] dp = new int[N +1];
dp[P]=1;for(int i =1; i <= K; i++){int leftUp = dp[1];// 左上角的值
for(int j =1; j <= N; j++){int tmp = dp[j];if(j ==1){
dp[j]= dp[j +1];}elseif(j == N){
dp[j]= leftUp;}else{
dp[j]= leftUp + dp[j +1];}
leftUp = tmp;}}return dp[M];}
public static void main(String[] args){
System.out.println(ways1(7,4,9,5));
System.out.println(ways2(7,4,9,5));
System.out.println(ways3(7,4,9,5));}}
deff1(N,E,rest,cur):if rest ==0:# return cur == E ? 1 : 0return1if cur == E else0if cur ==1:return f1(N,E,rest-1,2)if cur == N:return f1(N,E,rest-1,N-1)return f1(N,E,rest-1,cur-1)+ f1(N,E,rest-1,cur+1)deff2(N,E,rest,cur):if dp[rest][cur]!=-1:return dp[rest][cur]if rest ==0:
dp[rest][cur]=1if cur == E else0return dp[rest][cur]if cur ==1:
dp[rest][cur]= f2(N,E,rest-1,2,dp)elif cur == N:
dp[rest][cur]= f2(N, E, rest -1, N -1)else:
dp[rest][cur]= f2(N, E, rest -1, cur -1)+ f2(N, E, rest -1, cur +1)return dp[rest][cur]deffun3(N,start,aim,k):
dp =[]
dp[aim][0]=1for rest inrange(1,k):
dp[1][rest]= dp[2][rest -1]for cur inrange(2,N):
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]if __name__ =='__main__':# N E R C
f1(6,5,5,2)
dp =[]for i inrange(6-1):for j inrange(5-1):
dp[i][j]=-1print(dp)print(f2(6,5,5,2,dp))# f2(6,5,5,2,dp)
最小硬币数
package class07;
public classCode02_CoinsMin{
public static int minCoins1(int[] arr,int aim){if(arr == null || arr.length ==0|| aim <0){return-1;}return process(arr,0, aim);}// 当前考虑的面值是arr[i],还剩rest的钱需要找零
// 如果返回-1说明自由使用arr[i..N-1]面值的情况下,无论如何也无法找零rest
// 如果返回不是-1,代表自由使用arr[i..N-1]面值的情况下,找零rest需要的最少张数
public static int process(int[] arr,int i,int rest){// base case:
// 已经没有面值能够考虑了
// 如果此时剩余的钱为0,返回0张
// 如果此时剩余的钱不是0,返回-1if(i == arr.length){return rest ==0 ? 0:-1;}// 最少张数,初始时为-1,因为还没找到有效解
int res =-1;// 依次尝试使用当前面值(arr[i])0张、1张、k张,但不能超过rest
for(int k =0; k * arr[i]<= rest; k++){// 使用了k张arr[i],剩下的钱为rest - k * arr[i]// 交给剩下的面值去搞定(arr[i+1..N-1])intnext= process(arr, i +1, rest - k * arr[i]);if(next!=-1){// 说明这个后续过程有效
res = res ==-1 ? next+ k : Math.min(res,next+ k);}}return res;}
public static int minCoins2(int[] arr,int aim){if(arr == null || arr.length ==0|| aim <0){return-1;}int N = arr.length;int[][] dp = new int[N +1][aim +1];// 设置最后一排的值,除了dp[N][0]为0之外,其他都是-1for(int col =1; col <= aim; col++){
dp[N][col]=-1;}for(int i = N -1; i >=0; i--){// 从底往上计算每一行
for(int rest =0; rest <= aim; rest++){// 每一行都从左往右
dp[i][rest]=-1;// 初始时先设置dp[i][rest]的值无效
if(dp[i +1][rest]!=-1){// 下面的值如果有效
dp[i][rest]= dp[i +1][rest];// dp[i][rest]的值先设置成下面的值
}// 左边的位置不越界并且有效
if(rest - arr[i]>=0&& dp[i][rest - arr[i]]!=-1){if(dp[i][rest]==-1){// 如果之前下面的值无效
dp[i][rest]= dp[i][rest - arr[i]]+1;}else{// 说明下面和左边的值都有效,取最小的
dp[i][rest]= Math.min(dp[i][rest],
dp[i][rest - arr[i]]+1);}}}}return dp[0][aim];}//for test
public static int[] generateRandomArray(intlen,intmax){int[] arr = new int[(int)(Math.random()*len)+1];for(int i =0; i < arr.length; i++){
arr[i]=(int)(Math.random()*max)+1;}return arr;}
public static void main(String[] args){intlen=10;intmax=10;int testTime =10000;for(int i =0; i < testTime; i++){int[] arr = generateRandomArray(len,max);int aim =(int)(Math.random()*3*max)+max;if(minCoins1(arr, aim)!= minCoins2(arr, aim)){
System.out.println("ooops!");break;}}}}