
💡Yupureki:个人主页
✨个人专栏:《C++》 《算法》《Linux系统编程》《高并发内存池》《MySQL数据库》
🌸Yupureki🌸的简介:

目录
[1. 矩阵的最小路径和](#1. 矩阵的最小路径和)
[2. 「木」迷雾森林](#2. 「木」迷雾森林)
[3. 过河卒](#3. 过河卒)
[4. 方格取数](#4. 方格取数)
1. 矩阵的最小路径和
题目链接:

算法原理
状态表示
dp[ i ][ j ]表示走到第 i 行,第 j 列的格子时,最小的路径和是多少
状态方程
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + v[i][j];
初始化
dp[1][0] = 0;dp[0][1]=0
填表顺序
从上到下,从左到右
代码示例
cpp
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> v(n + 1, vector<int>(m + 1, 0xffffff));
vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0xffffff));
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
int num; cin >> num;
v[i][j] = num;
}
}
dp[1][0] = 0;
dp[0][1] = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + v[i][j];
}
cout << dp[n][m];
return 0;
}
2. 「木」迷雾森林
题目链接:

算法原理
状态表示
dp[ i ][ j ]表示走到第 i 行 第 j 列的格子时,不同的方案是多少
状态方程
如果第 i 行 第 j 列是树,此时不考虑
dp[i][j] = (dp[i+1][j] + dp[i][j-1])%2333;
初始化
dp[n+1][1] = 1;
填表顺序
从下往上,从左到右
代码示例
cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n, m;
cin >> n >> m;
vector<vector<int>> v(n + 1, vector<int>(m + 1, 1));
vector<vector<int>> dp(n + 2, vector<int>(m + 2));
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
int num; scanf("%d",&num);
v[i][j] = num;
}
}
dp[n+1][1] = 1;
for (int i = n; i >= 1; i--)
{
for (int j = 1; j <= m; j++)
{
if (v[i][j] == 1)
continue;
dp[i][j] = (dp[i+1][j] + dp[i][j-1])%2333;
}
}
cout << dp[1][m];
return 0;
}
3. 过河卒
题目链接:

算法原理
- 状态表示 :dp[i][j]表示:到达**(i,j)**位置的方案数。那么f[n][m]就是我们要的结果。
- 状态转移方程 :
- 如果(i,j)位置能走到,则到达(i,j)位置之前的一小步,有两种情况:
- 从(i-1,j)向下走一步,走到(i,j)此时的方案数为dp[i-1][j];
- 从(i,j-1)向右走一步,走到(i,j)此时的方案数为dp[i][j-1];
- 那么总方案数dp[i][j]=dp[i-1][j]+dp[i][j-1]。
- 如果[i,j位置走不到,dp[i][j]=0。
- 如果(i,j)位置能走到,则到达(i,j)位置之前的一小步,有两种情况:
- 初始化:我们可以给原始的矩阵多加一行多加一列,n,m,x,y全部+1,这样填任何一个位置都不会越界。然后初始化dp[1][0]=1或者dp[0][1]=1,保证后续填表正确即可。
- 填表顺序:从上往下每一行,每一行从左往右。
代码示例
cpp
#include <iostream>
#include <vector>
#include <set>
using namespace std;
int main()
{
int n, m, x, y; cin >> n >> m >> x >> y;
vector<vector<long long>> dp(n + 1, vector<long long>(m + 1));
set<pair<int,int>> um;
um.insert({ x,y });
um.insert({ x + 1,y + 2 }); um.insert({ x + 2,y + 1 });
um.insert({ x + 1,y - 2 }); um.insert({ x + 2,y - 1 });
um.insert({ x - 1,y + 2 }); um.insert({ x - 2,y + 1 });
um.insert({ x - 1,y - 2 }); um.insert({ x - 2,y - 1 });
if(um.find({0,0}) == um.end())
dp[0][0] = 1;
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= m; j++)
{
long long n1 = 0;
long long n2 = 0;
if (i > 0)
n1 = dp[i - 1][j];
if (j > 0)
n2 = dp[i][j - 1];
if (i == 0 && j == 0 || um.find({i,j}) != um.end())
continue;
dp[i][j] = n1 + n2;
}
}
cout << dp[n][m];
return 0;
}
4. 方格取数
题目链接:

算法原理
- 状态转移 :我们不能用贪心算法或是使用两次dp,都能找出反例。最好的方法便是让两个dp同时进行 。既然是同时进行的,我们会发现在任意时刻两个dp执行流走过的步数是一定的,我们记为sum,如果知道了第一个dp的i1,第二个dp的i2,那么就能计算出j1和j2(j1 = sum - i1,j2 = sum - j2)。因此我们令dp[ sum ][ i1 ][ i2 ]:当步数为sum,第一条路为[ i1 ][ sum - i1],第二条路为[ i2 ][ sum - i2 ]时,此时的得到数的最大值
- 状态方程 :两个dp流,走到[i1][j1],[i2][j2]时,有四种情况:
- 从[i1-1][j1]和[i2-1][j2]走到
- 从[i1][j1-1]和[i2-1][j2]走到
- 从[i1][j1-1]和[i2][j2-1]走到
- 从[i1][j1-1]和[i2][j2-1]走到
- 那么dp[sum][i1][i2] = max(dp[sum-1][i1][i2],dp[sum-1][i1-1][i2],dp[sum-1][i1-1][i2-1],dp[sum-1][i1][i2-1]) + v[i1][sum - i1] + v[i2][sum - i2](如果i1 == i2,则只能加一次)
- 初始化:dp[1][0] = 0;dp[0][1] = 0
- 填表顺序:sum从1到2 * n的过程中,每次从上到下,从左到右填表
代码示例
cpp
#include <iostream>
#include <vector>
using namespace std;
int dp[20][10][10];
int v[10][10];
int main()
{
int n; cin >> n;
int a, b, c;
while (cin >> a >> b >> c, c)
{
v[a][b] = c;
}
for(int sum = 1;sum <= 2 * n;sum++)
{
for(int i1 = 1;i1<=n;i1++)
{
for(int i2 = 1;i2<=n;i2++)
{
int j1 = sum - i1;
int j2 = sum - i2;
if(j1 <= 0 || j2 <= 0 || j1 > n || j2 > n)
continue;
int r1 = dp[sum-1][i1 - 1][i2-1];
int r2 = dp[sum-1][i1][i2-1];
int r3 = dp[sum-1][i1 - 1][i2];
int r4 = dp[sum-1][i1][i2];
if(i1 == i2)
dp[sum][i1][i2] = max(r1,max(r2,max(r3,r4))) + v[i1][j1];
else
dp[sum][i1][i2] = max(r1,max(r2,max(r3,r4))) + v[i1][j1] + v[i2][j2];
}
}
}
cout << dp[2 * n][n][n];
return 0;
}