左神算法与数据结构——基础提升递归转动态规划

暴力递归和动态规划

机器人

在这里插入图片描述

没什么技巧,框框解就行

在这里插入图片描述

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 总共有N个位置
//现在在第i个位置
//剩下rest步
//需要到end位置
int process1(int N, int i, int rest, int end) {
    if (rest == 0) {
        return i == end ? 1 : 0;
    }
    if (i == 1) {
        return process1(N, 2, rest - 1, end);
    }
    if (i == N) {
        return process1(N, N - 1, rest - 1, end);
    }
    return process1(N, i + 1, rest - 1, end) + process1(N, i - 1, rest - 1, end);

}

int process2(int N, int i, int rest, int end, vector<vector<int>> dp) {
    if (dp[rest][i] != -1) {
        return dp[rest][i];
    }
    if (rest == 0) {
        dp[rest][i] = i == end ? 1 : 0;
    }
    else if (i == 1) {
        dp[rest][i] = process2(N, 2, rest - 1, end, dp);
    }
    else if (i == N) {
        dp[rest][i] = process2(N, N - 1, rest - 1, end, dp);
    }
    else {
        dp[rest][i] = process2(N, i - 1, rest - 1, end, dp) + process2(N, i + 1, rest - 1, end, dp);
    }
    return dp[rest][i];

}

int robot2(int N, int i, int rest, int end) {
    vector<vector<int>> dp(rest + 1, vector<int>(N + 1));//rest + 1行,N + 1列的二维数组
    for (int row = 0; row < dp.size(); row++) {
        for (int col = 0; col < dp[0].size(); col++) {
            dp[row][col] = -1;
        }
    }
    return process2(N, i, rest, end, dp);
}

int process3(int N, int i, int rest, int end, vector<vector<int>> dp) {
    for (int i = 1; i < dp[0].size(); i++) {
        dp[0][i] = i == end ? 1 : 0;
    }
    for (int i = 1; i < dp.size(); i++) {
        for (int j = 1; j < dp[0].size(); j++) {
            if (j == 1) {
                dp[i][1] = dp[i - 1][2];
            }
            else if (j == N) {
                dp[i][N] = dp[i - 1][N - 1];
            }
            else {
                dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j + 1];
            }
        }
    }
    return dp[rest][i];
}

int robot3(int N, int i, int rest, int end) {
    vector<vector<int>> dp(rest + 1, vector<int>(N + 1));//rest + 1行,N + 1列的二维数组
    return process3(N, i, rest, end, dp);
}

int main()
{
    cout << process1(5, 2, 3, 3) << endl;
    cout << robot2(5, 2, 3, 3) << endl;
    cout << robot3(5, 2, 3, 3) << endl;
}

硬币

在这里插入图片描述

// arr表示硬币数组
// i表示现在遍历到第i个硬币了
// rest表示剩下需要多少钱
int process1(vector<int> arr, int i, int rest) {
    if (i == arr.size()) {// 全部遍历完了
        return rest == 0 ? 0 : -1;// 刚刚组合完,就不需要再拿一个了,因此返回0,否则表示不符合,返回-1
    }
    int res = -1;// 记录最小的个数
    for (int k = 0; k * arr[i] <= rest; k++) {// 拿0,1,2···个硬币,但保证不得超过rest
        int next = process1(arr, i + 1, rest - k * arr[i]);// 拿了k个后,i+1后最少钱数
        if (next != -1) {// 后续有可行结果
            res = res == -1 ? next + k : min(res, next + k);
        }
    }
    return res;
}

拿牌

在这里插入图片描述

法1:利用递归

int s1(vector<int> arr, int L, int R);

int f1(vector<int> arr, int L, int R) {
    if (L == R) {
        return arr[L];
    }
    return max(arr[L] + s1(arr, L + 1, R), arr[R] + s1(arr, L, R - 1));
}

int s1(vector<int> arr, int L, int R) {
    if (R == L) {
        return 0;
    }
    return min(f1(arr, L + 1, R), f1(arr, L, R - 1));
}

int getMax1(vector<int> arr) {
    return max(f1(arr, 0, arr.size() - 1), s1(arr, 0, arr.size() - 1));
}

法2:加入记忆矩阵

int s2(vector<int> arr, int L, int R, vector<vector<int>>& dp);

int f2(vector<int> arr, int L, int R, vector<vector<int>>& dp) {
    if (dp[L][R] != -1) {
        return dp[L][R];
    }
    if (L == R) {
        return arr[L];
    }
    dp[L][R] = max(arr[L] + s2(arr, L + 1, R, dp), arr[R] + s2(arr, L, R - 1, dp));
    return dp[L][R];
}

int s2(vector<int> arr, int L, int R, vector<vector<int>>& dp) {
    if (L == R) {
        return 0;
    }
    return min(f2(arr, L + 1, R, dp), f2(arr, L, R - 1, dp));
}

int getMax2(vector<int> arr) {
    vector<vector<int>> dp(4, vector<int>(4));
    for (int i = 0; i < dp.size(); i++) {
        for (int j = 0; j < dp[0].size(); j++) {
            dp[i][j] = -1;
        }
    }
    return max(f2(arr, 0, arr.size() - 1, dp), s2(arr, 0, arr.size() - 1, dp));
}

法3:动态规划

在这里插入图片描述

利用二维矩阵进行记录,其中代码中一般位置的搜索程序为亮点

int getMax3(vector<int> arr) {
    int size = arr.size();
    vector<vector<int>> f(size, vector<int>(size));
    vector<vector<int>> s(size, vector<int>(size));
    for (int i = 0; i < size; i++) {
        f[i][i] = arr[i];// 将f矩阵的对角线赋值
    }
    for (int j = 0; j < size; j++) {
        for (int i = j - 1; i >= 0; i--) {
            f[i][j] = max(arr[i] + s[i + 1][j], arr[j] + s[i][j - 1]);
            s[i][j] = min(f[i + 1][j], f[i][j - 1]);
        }
    }
    return max(f[0][size - 1], s[0][size - 1]);
}

象棋中马的跳法

在这里插入图片描述

棋盘大小9行10列,马开始固定位置(0, 0),目标位置为(a, b),需要走k步,则有几种方法

int process1(int x, int y, int rest) {
    if (x < 0 || x > 8 || y < 0 || y > 9) {
        return 0;
    }
    if (rest == 0) {
        return (x == 0 && y == 0) ? 1 : 0;
    }
    return process1(x + 2, y + 1, rest - 1) + process1(x + 1, y + 2, rest - 1)
        + process1(x - 1, y + 2, rest - 1) + process1(x - 2, y + 1, rest - 1)
        + process1(x - 2, y - 1, rest - 1) + process1(x - 1, y - 2, rest - 1)
        + process1(x + 1, y - 2, rest - 1) + process1(x + 2, y - 1, rest - 1);
}

void getHorse1(int a, int b, int k) {
    cout << process1(a, b, k) << endl;
}
int getValue(vector<vector<vector<int>>> dp, int x, int y, int z) {
    if (x < 0 || x > 8 || y < 0 || y > 9 || z < 0) {
        return 0;
    }
    return dp[x][y][z];
}

void getHorse2(int a, int b, int k) {
    vector<vector<vector<int>>> dp(k + 1,vector<vector<int>>(10, vector<int>(11)));
    dp[0][0][0] = 1;
    for (int rest = 1; rest < k + 1; rest++) {
        for (int y = 0; y < 10; y++) {
            for (int x = 0; x < 9; x++) {
                dp[x][y][rest] += getValue(dp, x + 2, y + 1, rest - 1);
                dp[x][y][rest] += getValue(dp, x + 1, y + 2, rest - 1);
                dp[x][y][rest] += getValue(dp, x - 1, y + 2, rest - 1);
                dp[x][y][rest] += getValue(dp, x - 2, y + 1, rest - 1);
                dp[x][y][rest] += getValue(dp, x - 2, y - 1, rest - 1);
                dp[x][y][rest] += getValue(dp, x - 1, y - 2, rest - 1);
                dp[x][y][rest] += getValue(dp, x + 1, y - 2, rest - 1);
                dp[x][y][rest] += getValue(dp, x + 2, y - 1, rest - 1);
            }
        }
    }
    cout<< dp[a][b][k] << endl;
}

Bob

在这里插入图片描述

void process1(int m, int n, int i, int j, int k, vector<int>& res) {
    if (k == 0) {
        if (i >= n || i < 0 || j < 0 || j >= m) {
            res[1]++;
            return;
        }
        else {
            res[0]++;
            return;
        }
    }
    process1(m, n, i - 1, j, k - 1, res);
    process1(m, n, i, j - 1, k - 1, res);
    process1(m, n, i, j + 1, k - 1, res);
    process1(m, n, i + 1, j, k - 1, res);
    return;
}

string Bob1(int m, int n, int i, int j, int k) {
    vector<int> res(2,0); // res[0]表示生存,res[1]表示死亡
    process1(m, n, i, j, k, res);
    double p = (double)res[0] / (double)(res[1] + res[0]);
    p = p * 100;
    return to_string(p);
}

这题总是有问题,待调整

换钱的最少货币数

在这里插入图片描述

// 表示arr[i]以后开始选取,剩下了rest元
int process1(vector<int> arr, int i, int rest) {
    if (i == arr.size()) {
        return rest == 0 ? 0 : -1;// 当钱数刚好为0时候,不用再选返回0张,其余返回不可行
    }
    int res = -1;
    for (int t = 0; arr[i] * t <= rest; t++) {
        // next为当选取t张时,后续可行的张数
        int next = process1(arr, i + 1, rest - arr[i] * t);
        if (next != -1) {// 后续可行
            res = res == -1 ? t + next : min(res, t + next);
        }
    }
    return res;
}

void coinMin1(vector<int> arr, int rest) {
    if (arr.size() < 1) {
        return;
    }
    cout << process1(arr, 0, rest) << endl;
}

void coinMin2(vector<int> arr, int rest) {
    if (arr.size() < 1) {
        return;
    }
    vector<vector<int>> dp(arr.size() + 1, vector<int>(rest + 1));
    for (int i = 1; i <= rest; i++) {
        dp[arr.size()][i] = -1;
    }
    for (int i = arr.size() - 1; i >= 0; i--) {
        for (int j = 0; j <= rest; j++) {
            dp[i][j] = -1;
            if (dp[i + 1][j] != -1) {
                dp[i][j] = dp[i + 1][j];
            }
            if (j - arr[i] >= 0 && dp[i][j - arr[i]] != -1) {
                if (dp[i][j] == -1) {
                    dp[i][j] = dp[i][j - arr[i]] + 1;
                }
                else {
                    dp[i][j] = min(dp[i][j], dp[i][j - arr[i]] + 1);
                }
            }
        }
    }
    cout << dp[0][rest] << endl;
}

方法论

  • 尝试方法为从左到右,或者范围上尝试,基本能解决问题
  • 需要考虑可变参数的维数以及可变参数的个数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值