暴力递归和动态规划
机器人
没什么技巧,框框解就行
#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;
}
方法论
- 尝试方法为从左到右,或者范围上尝试,基本能解决问题
- 需要考虑可变参数的维数以及可变参数的个数