• 第18节 动态规划一讲


    1假设有排成一行的N个位置记为1~N,N一定大于或等于2
    开始时机器人在其中的M位置上(M一定是1~N中的一个)
    如果机器人来到1位置,那么下一步只能往右来到2位置;
    如果机器人来到N位置,那么下一步只能往左来到N-1位置;
    如果机器人来到中间位置,那么下一步可以往左走或者往右走;
    规定机器人必须走K步,最终能来到P位置(P也是1~N中的一个)的方法有多少种
    给定四个参数 N、M、K、P,返回方法数

    动态规划:如果在调用过程中有重复调用过程就将他存起来

    比如递归求斐波那契数列,中间有不少重复过程

     递归策略:

    1. #include
    2. using namespace std;
    3. class Solution {
    4. public:
    5. int ways1(int N, int start, int aim, int K) {
    6. if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
    7. return -1;
    8. }
    9. return process1(start, K, aim, N);
    10. }
    11. / 机器人当前来到的位置是cur,
    12. // 机器人还有rest步需要去走,
    13. // 最终的目标是aim,
    14. // 有哪些位置?1~N
    15. // 返回:机器人从cur出发,走过rest步之后,最终停在aim的方法数,是多少?
    16. private:
    17. int process1(int cur, int rest, int aim, int N) {
    18. if (rest == 0) {
    19. return cur == aim ? 1 : 0;
    20. }
    21. if (cur == 1) {
    22. return process1(2, rest - 1, aim, N);
    23. }
    24. if (cur == N) {
    25. return process1(N - 1, rest - 1, aim, N);
    26. }
    27. return process1(cur - 1, rest - 1, aim, N) + process1(cur + 1, rest - 1, aim, N);
    28. }
    29. };

    这个递归来进行优化

    该递归中出现了重复解

    cur范围1到n

    rest范围0到k

    准备一张dp表,先全设为-1,表示没算过这个过程

    1. #include
    2. using namespace std;
    3. class Solution {
    4. public:
    5. int ways2(int N, int start, int aim, int K) {
    6. if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
    7. return -1;
    8. }
    9. vectorint>> dp(N + 1, vector<int>(K + 1, -1));
    10. return process2(start, K, aim, N, dp);
    11. }
    12. private:
    13. int process2(int cur, int rest, int aim, int N, vectorint>>& dp) {
    14. if (dp[cur][rest] != -1) {
    15. return dp[cur][rest];
    16. }//算过的值就塞入缓存表
    17. int ans = 0;
    18. if (rest == 0) {
    19. ans = cur == aim ? 1 : 0;
    20. }
    21. else if (cur == 1) {
    22. ans = process2(2, rest - 1, aim, N, dp);
    23. }
    24. else if (cur == N) {
    25. ans = process2(N - 1, rest - 1, aim, N, dp);
    26. }
    27. else {
    28. ans = process2(cur - 1, rest - 1, aim, N, dp) + process2(cur + 1, rest - 1, aim, N, dp);
    29. }
    30. dp[cur][rest] = ans;//没算过的算出来了也塞入缓存表
    31. return ans;
    32. }
    33. };

     再往下优化,直接填这张动态规划表

     

    不要硬憋状态转移,要去想尝试策略

    1. #include
    2. using namespace std;
    3. class Solution {
    4. public:
    5. int ways3(int N, int start, int aim, int K) {
    6. if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
    7. return -1;
    8. }
    9. vectorint>> dp(N + 1, vector<int>(K + 1, 0));
    10. dp[aim][0] = 1;
    11. for (int rest = 1; rest <= K; rest++) {
    12. dp[1][rest] = dp[2][rest - 1];
    13. for (int cur = 2; cur < N; cur++) {
    14. dp[cur][rest] = dp[cur - 1][rest - 1] + dp[cur + 1][rest - 1];
    15. }
    16. dp[N][rest] = dp[N - 1][rest - 1];
    17. }
    18. return dp[start][K];
    19. }
    20. };

     2给定一个整型数组arr,代表数值不同的纸牌排成一条线
    玩家A和玩家B依次拿走每张纸牌
    规定玩家A先拿,玩家B后拿
    但是每个玩家每次只能拿走最左或最右的纸牌
    玩家A和玩家B都绝顶聪明
    请返回最后获胜者的分数

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. int f1(vector<int>& arr, int L, int R);
    6. int g1(vector<int>& arr, int L, int R);
    7. int win1(vector<int>& arr) {
    8. if (arr.empty()) {
    9. return 0;
    10. }
    11. int first = f1(arr, 0, arr.size() - 1);
    12. int second = g1(arr, 0, arr.size() - 1);
    13. return max(first, second);
    14. }
    15. int f1(vector<int>& arr, int L, int R) {
    16. if (L == R) {
    17. return arr[L];
    18. }
    19. int p1 = arr[L] + g1(arr, L + 1, R);
    20. int p2 = arr[R] + g1(arr, L, R - 1);
    21. return max(p1, p2);
    22. }
    23. int g1(vector<int>& arr, int L, int R) {
    24. if (L == R) {
    25. return 0;
    26. }
    27. int p1 = f1(arr, L + 1, R); // 对手拿走了L位置的数
    28. int p2 = f1(arr, L, R - 1); // 对手拿走了R位置的数
    29. return min(p1, p2);
    30. }
    31. int main() {
    32. vector<int> arr = {3, 9, 1, 2};
    33. cout << win1(arr) << endl; // 示例输入,输出结果根据实际情况可能不同
    34. return 0;
    35. }

     弄两张表进行记忆化缓存

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. int f2(vector<int>& arr, int L, int R, vectorint>>& fmap, vectorint>>& gmap);
    6. int g2(vector<int>& arr, int L, int R, vectorint>>& fmap, vectorint>>& gmap);
    7. int win2(vector<int>& arr) {
    8. if (arr.empty()) {
    9. return 0;
    10. }
    11. int N = arr.size();
    12. vectorint>> fmap(N, vector<int>(N, -1));
    13. vectorint>> gmap(N, vector<int>(N, -1));
    14. int first = f2(arr, 0, arr.size() - 1, fmap, gmap);
    15. int second = g2(arr, 0, arr.size() - 1, fmap, gmap);
    16. return max(first, second);
    17. }
    18. int f2(vector<int>& arr, int L, int R, vectorint>>& fmap, vectorint>>& gmap) {
    19. if (fmap[L][R] != -1) {
    20. return fmap[L][R];
    21. }
    22. int ans = 0;
    23. if (L == R) {
    24. ans = arr[L];
    25. } else {
    26. int p1 = arr[L] + g2(arr, L + 1, R, fmap, gmap);
    27. int p2 = arr[R] + g2(arr, L, R - 1, fmap, gmap);
    28. ans = max(p1, p2);
    29. }
    30. fmap[L][R] = ans;
    31. return ans;
    32. }
    33. int g2(vector<int>& arr, int L, int R, vectorint>>& fmap, vectorint>>& gmap) {
    34. if (gmap[L][R] != -1) {
    35. return gmap[L][R];
    36. }
    37. int ans = 0;
    38. if (L != R) {
    39. int p1 = f2(arr, L + 1, R, fmap, gmap); // 对手拿走了L位置的数
    40. int p2 = f2(arr, L, R - 1, fmap, gmap); // 对手拿走了R位置的数
    41. ans = min(p1, p2);
    42. }
    43. gmap[L][R] = ans;
    44. return ans;
    45. }
    46. int main() {
    47. vector<int> arr = {3, 9, 1, 2};
    48. cout << win2(arr) << endl; // 示例输入,输出结果根据实际情况可能不同
    49. return 0;
    50. }

     

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. int win3(vector<int>& arr) {
    6. if (arr.empty()) {
    7. return 0;
    8. }
    9. int N = arr.size();
    10. vectorint>> fmap(N, vector<int>(N));
    11. vectorint>> gmap(N, vector<int>(N));
    12. for (int i = 0; i < N; i++) {
    13. fmap[i][i] = arr[i];
    14. }
    15. for (int startCol = 1; startCol < N; startCol++) {
    16. int L = 0;
    17. int R = startCol;
    18. while (R < N) {
    19. fmap[L][R] = max(arr[L] + gmap[L + 1][R], arr[R] + gmap[L][R - 1]);
    20. gmap[L][R] = min(fmap[L + 1][R], fmap[L][R - 1]);
    21. L++;
    22. R++;
    23. }
    24. }
    25. return max(fmap[0][N - 1], gmap[0][N - 1]);
    26. }
    27. int main() {
    28. vector<int> arr = {3, 9, 1, 2};
    29. cout << win3(arr) << endl; // 示例输入,输出结果根据实际情况可能不同
    30. return 0;
    31. }

     

     

     

  • 相关阅读:
    springboot大学生就业招聘网站java ssm
    大数据中间件——Kafka
    EfficientNet笔记
    STM8的C语言编程(8)--+UART应用
    一维和二维差分
    Redis的快速入门
    EGL函数翻译--eglInitialize
    论文阅读疑惑,算法问题,求余,控制问题
    Java基于SpringBoot的逍遥大药房管理平台
    Java TreeMap如何按照key或value降序排列呢?
  • 原文地址:https://blog.csdn.net/2201_75715662/article/details/136770112