日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

暴力递归到动态规划

發布時間:2024/3/13 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 暴力递归到动态规划 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

動態規劃就是暴力嘗試減少重復計算的技巧

1)找到什么可變參數可以代表一個遞歸狀態,也就是哪些參數一旦確定,返回值就確定了 2)把可變參數的所有組合映射成一張表,有 1 個可變參數就是一維表,2 個可變參數就 是二維表,...... 3)最終答案要的是表中的哪個位置,在表中標出 4)根據遞歸過程的 base case,把這張表的最簡單、不需要依賴其他位置的那些位置填好 值 5)根據遞歸過程非base case的部分,也就是分析表中的普遍位置需要怎么計算得到,那 么這張表的填寫順序也就確定了 6)填好表,返回最終答案在表中位置的值

暴力遞歸嘗試(從左至右\范圍)
->
轉化成記憶搜索
->
轉化成嚴格表結構的DP
->
觀察表結構進行優化

題目一:機器人達到指定位置方法數

題目: 假設有排成一行的 N 個位置,記為 1~N,N 一定大于或等于 2 開始時機器人在其中的 M 位 置上(M 一定是 1~N 中的一個),機器人可以往左走或者往右走 如果機器人來到 1 位置, 那 么下一步只能往右來到 2 位置;如果機器人來到 N 位置,那么下一步只能往左來到 N-1 位置。 規定機器人必須走 K 步,最終能來到 P 位置(P 也一定是 1~N 中的一個)的方法有多少種 給 定四個參數 N、M、K、P,返回方法數 ============================================================================================= 舉例: N=5,M=2,K=3,P=3 上面的參數代表所有位置為 1 2 3 4 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 所以返回方法數 3。 N=3,M=1,K=3,P=3 上面的參數代表所有位置為 1 2 3。 機器人最開始在 1 位置上,必須經過 3 步,最后到達 3 位置。怎么走也不可能,所以返回方法數 0。 package class08;/*** @title: RobotWalk* @Descriptor: 總共N個位置,從M點出發,還剩K步,返回最終能到達P的方法數* @Author DD* @Date: 2022/6/8 11:01* @Version 1.0*/public class RobotWalk {public static int way1(int N, int M, int K, int P) {if (N < 2 || K < 1 || M < 1 || M > N || P < 1 || P > N) {return 0;}return walk(N, M, K, P);}public static int walk(int N, int cur, int rest, int P) {if (rest == 0) {return cur == P ? 1 : 0;}// rest > 0 還可以繼續走if (cur == 1) {return walk(N, cur + 1, rest - 1, P);}if (cur == N) {return walk(N, cur - 1, rest - 1, P);}return walk(N, cur + 1, rest - 1, P) + walk(N, cur - 1, rest - 1, P);}public static int way2(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];for (int i = 0; i <= K; i++) {for (int j = 0; j <= N; j++) {dp[i][j] = -1;}}return walk2(N, M, K, P, dp);}public static int walk2(int N, int cur, int rest, int P, int[][] dp) {if (dp[rest][cur] != -1) {// 當前狀態之前已經計算過return dp[rest][cur];}// 之前沒計算過該狀態if (rest == 0) {dp[rest][cur] = cur == P ? 1 : 0;return dp[rest][cur];}// rest > 0 還可以繼續走if (cur == 1) {dp[rest][cur] = walk(N, cur + 1, rest - 1, P);return dp[rest][cur];} else if (cur == N) {dp[rest][cur] = walk(N, cur - 1, rest - 1, P);return dp[rest][cur];} else {dp[rest][cur] = walk(N, cur + 1, rest - 1, P) + walk(N, cur - 1, rest - 1, P);}return dp[rest][cur];}public static int way3(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];return walk3(N,M,K,P,dp);}public static int walk3(int N,int cur,int rest,int P,int[][] dp){// 參數無效直接返回0if (N < 2 || rest < 1 || cur < 1 || cur> N || P < 1 || P > N) {return 0;}dp[0][P] = 1;for (int i = 1; i <= rest; i++) {for (int j = 1; j <= N; j++) {if (j == 1) {dp[i][j] = dp[i - 1][2];} else if (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[rest][cur];}public static int way4(int N, int M, int K, int P) {// 嚴格表結構的動態規劃 -- 省空間版if (N < 2 || K < 1 || M < 1 || M > N || P < 1 || P > N) {return 0;}return walk4(N, M, K, P);}public static int walk4(int N, int M, int K, int P) {// 參數無效直接返回0if (N < 2 || K < 1 || M < 1 || M > N || P < 1 || P > N) {return 0;}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];} else if (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(way2(5, 2, 4, 4));System.out.println(way3(5,2,4,4));System.out.println(way4(5, 2, 4, 4));} }

題目二:換錢的最少貨幣數

【題目】 給定數組 arr,arr 中所有的值都為正數且不重復。 每個值代表一種面值的貨幣,每種面值 的貨幣可以使用任意張, 再給定一個整數 aim,代表要找的錢數,求組成 aim 的最少貨幣數。 【舉例】 arr=[5,2,3],aim=20 4張5元可以組成 20 元,其他的找錢方案都要使用更多張的貨幣,所以返回4。 arr=[5,2,3],aim=0 不用任何貨幣就可以組成 0 元,返回 0。 arr=[3,5],aim=2 根本無法組成 2 元,錢不能找開的情況下默認返回-1 package class08;/*** @title: minCoins* @Descriptor: 換錢的最少貨幣數* @Author DD* @Date: 2022/6/19 16:42* @Version 1.0*/public class minCoins {// 暴力遞歸版本public static int minCoins1(int[] arr, int aim) {if (aim == 0) {return 0;}return process1(arr, 0, aim);}public static int process1(int[] arr, int i, int rest) {// 從arr[i....] 中組出rest這么多錢,所用的最少貨幣數if (rest < 0) {// 之前的組合導致錢數大于aim 失敗return -1;}if (rest == 0) {// 之前的組合剛好湊出了aim 無需使用之后的貨幣了return 0;}// rest>0if (i == arr.length) {// 之前的組合把錢用完了 沒有可供湊數的return -1;}// rest>0 并且 還有可供湊數的錢int p1 = process1(arr, i + 1, rest); // 沒有選擇i位置上的錢int p2Next = process1(arr, i + 1, rest - arr[i]); // 選了i位置上的錢if (p1 == -1 && p2Next == -1) { // 選不選都不能滿足要求return -1;} else {if (p1 == -1) {return p2Next + 1;}if (p2Next == -1) {return p1;}return Math.min(p1, p2Next + 1);}}public static int minCoins2(int[] arr, int aim) {// 記憶搜索版本if (aim == 0) {return 0;}int[][] dp = new int[arr.length + 1][aim + 1];for (int i = 0; i < arr.length + 1; i++) {for (int j = 0; j < aim + 1; j++) {dp[i][j] = -2; // 初始化記憶數組 -2表示未訪問過}}return process2(arr, 0, aim, dp);}public static int process2(int[] arr, int i, int rest, int[][] dp) {if (rest < 0) {// 之前的組合導致錢數大于aim 失敗return -1;}if (rest == 0) {// 之前的組合剛好湊出了aim 無需使用之后的貨幣了dp[i][rest] = 0;} else if (i == arr.length) {// rest>0// 之前的組合把錢用完了 沒有可供湊數的dp[i][rest] = -1;} else {// rest>0 并且 還有可供湊數的錢int p1 = process1(arr, i + 1, rest); // 沒有選擇i位置上的錢int p2Next = process1(arr, i + 1, rest - arr[i]); // 選了i位置上的錢if (p1 == -1 && p2Next == -1) { // 選不選都不能滿足要求dp[i][rest] = -1;} else {if (p1 == -1) {dp[i][rest] = p2Next + 1;} else if (p2Next == -1) {dp[i][rest] = p1;} else {dp[i][rest] = Math.min(p2Next + 1, p1);}}}return dp[i][rest];}public static int minCoins3(int[] arr, int aim) {// 嚴格表結構的動態規劃int N = arr.length;int[][] dp = new int[N + 1][aim + 1];for (int col = 1; col < aim + 1; col++) {dp[N][col] = -1;}// for (int i = 0; i < N + 1; i++) { // for (int j = 0; j < aim + 1; j++) { // System.out.print(dp[i][j]); // if (j == aim) { // System.out.println(); // } // } // } // System.out.println("=============");for (int i = N - 1; i >= 0; i--) {for (int rest = 1; rest <= aim; rest++) {// rest>0 并且 還有可供湊數的錢 // int p1 = process1(arr, i + 1, rest); // 沒有選擇i位置上的錢int p1 = dp[i + 1][rest]; // int p2Next = process1(arr, i + 1, rest - arr[i]); // 選了i位置上的錢int p2Next = -1;if (rest - arr[i] >= 0) {p2Next = dp[i + 1][rest - arr[i]];}if (p1 == -1 && p2Next == -1) { // 選不選都不能滿足要求dp[i][rest] = -1;} else {if (p1 == -1) {dp[i][rest] = p2Next + 1;} else if (p2Next == -1) {dp[i][rest] = p1;} else {dp[i][rest] = Math.min(p1, p2Next + 1);}}}} // for (int i = 0; i < N + 1; i++) { // for (int j = 0; j < aim + 1; j++) { // System.out.print(dp[i][j]); // if (j == aim) { // System.out.println(); // } // } // }return dp[0][aim];}public static void main(String[] args) {int[] money = {2, 3, 5, 7, 2};System.out.println(minCoins1(money, 2));System.out.println(minCoins1(money, 5));System.out.println(minCoins1(money, 150));System.out.println(minCoins1(money, 10));System.out.println("=======================");System.out.println(minCoins2(money, 2));System.out.println(minCoins2(money, 5));System.out.println(minCoins2(money, 150));System.out.println(minCoins2(money, 10));System.out.println("======================="); // minCoins3(money, 10);System.out.println(minCoins3(money, 2));System.out.println(minCoins3(money, 5));System.out.println(minCoins3(money, 150));System.out.println(minCoins3(money, 10));} }

題目三:排成一條線的紙牌博弈問題

給定一個整型數組arr,代表數值不同的紙牌排成一條線。玩家A和玩家B依次拿走每張紙牌, 規定玩家A先拿,玩家B后拿,但是每個玩家每次只能拿走最左或最右的紙牌, 玩家A 和玩家B都絕頂聰明。請返回最后獲勝者的分數。 【舉例】 arr=[1,2,100,4] 開始時,玩家A只能拿走1或4。如果開始時玩家A拿走1,則排列變為[2,100,4], 接下來 玩家 B可以拿走2或4,然后繼續輪到玩家A... 如果開始時玩家A拿走4,則排列變為[1,2,100],接下來玩家B可以拿走1或100,然后繼續輪到玩家A... 玩家A作為絕頂聰明的人不會先拿4,因為拿4之后,玩家B將拿走100。 所以玩家A會先拿1,讓排列變為[2,100,4],接下來玩家B不管怎么選,100都會被玩家 A拿走。 玩家A會獲勝, 分數為101。所以返回101.

package class08;/*** @title: cardInLine* @Descriptor: 給定一個整型數組arr,代表數值不同的紙牌排成一條線。玩家A和玩家B依次拿走每張紙牌,* 規定玩家A先拿,玩家B后拿,但是每個玩家每次只能拿走最左或最右的紙牌,玩家A和玩家B都絕頂聰明。請返回最后獲勝者的分數。* @Author DD* @Date: 2022/5/30 17:07* @Version 1.0*/public class cardInLine {public static int win1(int[] arr) {if (arr == null || arr.length == 0) {return 0;}return Math.max(f(arr, 0, arr.length - 1), s(arr, 0, arr.length - 1));}// 先手 在arr的i~j范圍內所能得到的最大分數public static int f(int[] arr, int i, int j) {if (i == j) { // 牌組中僅剩一張牌return arr[i]; // 因為是先手 所以能得到這張牌}// 牌組中至少余兩張// 從左右兩端選擇一張后,對于剩余的牌組來說 肯定是別人先取一張 之后輪到自己 ==> 成為新牌組的后手// (當前所選牌+后手時所能拿到的最大分數) ==> 即為最終最終總分// 返回最終總分大的return Math.max(arr[i] + s(arr, i + 1, j), arr[j] + s(arr, i, j - 1));}// 后手 在arr的i~j范圍內所能得到的最大分數public static int s(int[] arr, int i, int j) {if (i == j) { // 牌組中僅剩一張牌return 0; // 因為是后手 所以得不到這張牌}int p1 = f(arr, i + 1, j); // 對手選了arr[i]后最終所能達到的最大分數int p2 = f(arr, i, j - 1); // 對手選了arr[j]后最終所能達到的最大分數// 讓對手所得到的分數盡可能的小return Math.min(p1, p2);}public static int win2(int[] arr) {// 范圍遞歸轉DP 先畫圖if (arr == null || arr.length == 0) {return 0;}int[][] f = new int[arr.length][arr.length];int[][] s = new int[arr.length][arr.length];for (int j = 0; j < arr.length; j++) {f[j][j] = arr[j];for (int i = j - 1; i >= 0; i--) {f[i][j] = Math.max(arr[i] + s[i + 1][j], arr[j] + s[i][j - 1]);s[i][j] = Math.min(f[i + 1][j], f[i][j - 1]);}}return Math.max(f[0][arr.length - 1], s[0][arr.length - 1]);}public static void main(String[] args) {int[] arr = {1, 9, 1};System.out.println(win1(arr));System.out.println(win2(arr)); // System.out.println(win3(arr));} }

題目四:想起中馬的跳法(三維嘗試改DP)

【題目】 請同學們自行搜索或者想象一個象棋的棋盤,然后把整個棋盤放入第一象限,棋盤的最左下 角是(0,0)位置。 那么整個棋盤就是橫坐標上9條線、縱坐標上10條線的一個區域。 給你三個 參數,x,y,k, 返回如果“馬”從(0,0)位置出發,必須走k步,最后落在(x,y)上的方法數有多少種

要第Step步跳到目標位置,只需找(Step-1)步跳到目標周圍(下一步跳一下就可以到目標)
抽象成三維表結構

package class08;/*** @title: horseJump* @Descriptor: 象棋中馬的跳法* @Author DD* @Date: 2022/6/20 14:57* @Version 1.0*/public class horseJump {public static int getWays(int x, int y, int step) {return process(x, y, step);}public static int process(int x, int y, int step) {if (x < 0 || x > 8 || y < 0 || y > 9) {return 0;}if (step == 0) {return (x == 0 && y == 0) ? 1 : 0;}return process(x - 1, y + 2, step - 1)+ process(x + 1, y + 2, step - 1)+ process(x + 2, y + 1, step - 1)+ process(x + 2, y - 1, step - 1)+ process(x + 1, y - 2, step - 1)+ process(x - 1, y - 2, step - 1)+ process(x - 2, y - 1, step - 1)+ process(x - 2, y + 1, step - 1);}public static int dpWays(int x, int y, int step) {if (x < 0 || x > 8 || y < 0 || y > 9 || step < 0) {return 0;}int[][][] dp = new int[9][10][step + 1];dp[0][0][0] = 1;for (int h = 1; h <= step; h++) {for (int r = 0; r < 9; r++) {for (int c = 0; c < 10; c++) {dp[r][c][h] += getValue(dp, r - 1, c + 2, h - 1);dp[r][c][h] += getValue(dp, r + 1, c + 2, h - 1);dp[r][c][h] += getValue(dp, r + 2, c + 1, h - 1);dp[r][c][h] += getValue(dp, r + 2, c - 1, h - 1);dp[r][c][h] += getValue(dp, r + 1, c - 2, h - 1);dp[r][c][h] += getValue(dp, r - 1, c - 2, h - 1);dp[r][c][h] += getValue(dp, r - 2, c - 1, h - 1);dp[r][c][h] += getValue(dp, r - 2, c + 1, h - 1);}}}return dp[x][y][step];}public static int getValue(int[][][] dp, int row, int col, int step) {if (row < 0 || row > 8 || col < 0 || col > 9) {return 0;}return dp[row][col][step];}public static void main(String[] args) {int x = 7;int y = 7;int step = 10;System.out.println(getWays(x, y, step));System.out.println(dpWays(x, y, step));} }

題目五:可重復使用面值湊目標錢數

【題目】 arr內都是正數,沒有重復值,每一個值代表一種面額的貨幣,每一種都可以重復使用 最終要找零錢數是aim 返回不同組合的方法數 ================================== [舉例] arr = [2,3,5] 希望湊成10元 case1: 2,2,2,2,2 case2: 2,3,5 case3: 2,2,3,3 case4: 5,5 package class08;/*** @title: coinsWays* @Descriptor: 使用數組中提供的面值(可以重復使用)組合成目標面值 返回組合數* @Author DD* @Date: 2022/6/20 18:56* @Version 1.0*/public class coinsWays {// arr內都是正數,沒有重復值,每一個值代表一種面額的貨幣,每一種都可以重復使用// 最終要找零錢數是aim// 返回不同組合的方法數public static int way1(int[] arr, int aim) {return process(arr, 0, aim);}// 使用arr[index...]中的所有面值,湊成rest,返回所有湊法 -- 暴力遞歸public static int process(int[] arr, int index, int rest) {if (index == arr.length) { // 所有面值都已嘗試結束return rest == 0 ? 1 : 0;}// 使用 x張 arr[index]面值的貨幣 需要x*arr[index]<rest ==> 不越界int ways = 0;for (int zhang = 0; zhang * arr[index] <= rest; zhang++) {ways += process(arr, index + 1, rest - zhang * arr[index]);}return ways;}// 記憶搜索public static int way2(int[] arr, int aim) {int N = arr.length;int[][] dp = new int[N + 1][aim + 1];return process2(arr, 0, aim, dp);}private static int process2(int[] arr, int index, int rest, int[][] dp) {if (index == arr.length) {dp[index][rest] = rest == 0 ? 1 : 0;return dp[index][rest];}int ways = 0;for (int zhang = 0; zhang * arr[index] <= rest; zhang++) {ways += process2(arr, index + 1, rest - zhang * arr[index], dp);}dp[index][rest] = ways;return dp[index][rest];}// 嚴格表結構的動態規劃public static int way3(int[] arr, int aim) {return process3(arr, 0, aim);}public static int process3(int[] arr, int index, int aim) {int N = arr.length;int[][] dp = new int[N + 1][aim + 1];dp[N][0] = 1;for (int i = N - 1; i >= 0; i--) {for (int j = 0; j <= aim; j++) {int ways = 0;for (int zhang = 0; zhang * arr[index] <= aim; zhang++) {ways += process2(arr, index + 1, aim - zhang * arr[index], dp);}dp[i][j] = ways;}}return dp[0][aim];}// 表結構的優化// 當前數據依賴 arr[index+1][rest] 和 arr[index][rest - arr[index]](優化的點就在于避免了重復計算該項)public static int way4(int[] arr, int aim) {int N = arr.length;int[][] dp = new int[N + 1][aim + 1];dp[N][0] = 1;for (int i = N - 1; i >= 0; i--) {for (int j = 0; j <= aim; j++) {dp[i][j] = dp[i + 1][j];if (j - arr[i] >= 0) {dp[i][j] += dp[i][j - arr[i]];}}}return dp[0][aim];}public static void main(String[] args) {int[] money = {2, 3, 5}; // System.out.println(way1(money, 1));System.out.println(way3(money, 10));System.out.println(way3(money, 2));System.out.println(way4(money, 10));System.out.println(way4(money, 2));} }

總結

以上是生活随笔為你收集整理的暴力递归到动态规划的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 口述3p做爰全过程 | 韩国伦理av | 蜜桃一区二区三区 | 人人草人人插 | 空姐毛片 | 内射后入在线观看一区 | 中文字幕丝袜诱惑 | 尤物天堂 | 欧美伊人网 | 男女啪啪网站免费 | 久久久亚洲精品视频 | 精品一区二区三区中文字幕 | 午夜一区二区三区 | 小色瓷导航 | 欧美日韩免费在线观看 | 国产乱来 | 蜜桃视频在线观看一区 | 国产视频久久 | 日本女人一区二区三区 | 97免费公开视频 | 日韩av片在线 | 美女大黄网站 | 欧美性大战久久久久xxx | 国产精品91一区二区 | 九九视频在线观看 | 丁香六月综合 | 思思99精品视频在线观看 | 91免费精品 | 成人国产一区二区三区 | 奇米在线777 | 又黄又爽又色的视频 | 91在线精品一区二区三区 | 成人在线高清视频 | 一本色道久久加勒比精品 | 日本少妇裸体做爰高潮片 | 成人看 | 国产成人精品一区二区在线小狼 | 国模私拍一区二区 | 欧美性一区二区三区 | 精品视频一二三区 | 中文字幕永久免费 | 大咪咪dvd | 欧美色图网址 | 欧美一区二区三区免费观看 | 少妇xxx | 网站免费在线观看 | 色爱综合 | 黑帮大佬和我的三百六十五天 | 国产四区视频 | 在线看片你懂得 | 日韩天天 | 欧美综合亚洲图片综合区 | 亚洲少妇视频 | 极品探花在线观看 | 欧美片网站免费 | 伊人春色影院 | 色啊色| 日本黄色大片免费 | 美女写真福利视频 | 成人一区二区免费视频 | 99在线视频观看 | 放荡闺蜜高h苏桃情事h | 亚洲AV无码成人片在线观看 | 东南亚毛片 | 久久精品一二三 | 99riav国产精品视频 | 扒开伸进免费视频 | 亚洲最大色网站 | 欧美电影一区二区三区 | 激情内射亚洲一区二区三区爱妻 | 小珊的性放荡羞辱日记 | 亚洲成人三级 | 国产高清精品软件丝瓜软件 | 中国无码人妻丰满熟妇啪啪软件 | av色欲无码人妻中文字幕 | 欧美激情精品久久久久久 | 久久九九色| 波多野一区二区三区 | 爱插美女网 | 欧美天天视频 | 2024国产精品 | 91麻豆产精品久久久久久 | www好男人| 欧美黑人一级爽快片淫片高清 | 尤物一区二区 | 猛男大粗猛爽h男人味 | 一区在线播放 | 久久视频一区二区三区 | 色综合色综合色综合 | 国产精品久久久久久久久久久久午夜片 | 爱看av在线 | 色乱码一区二区三区熟女 | 强制憋尿play黄文尿奴 | av播放在线 | 久久久91 | 成人手机av| 国产九九精品 | 国产xxxx性hd极品 | 日韩avav |