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

目录
[1. 台阶问题](#1. 台阶问题)
[2. 最大子段和](#2. 最大子段和)
[3. 传球游戏](#3. 传球游戏)
1. 台阶问题
题目链接:

算法原理
经典的动态规划题目
1. 状态表示:
dp[i]表示走到第i号阶梯的方式
dp[n]为最终结果
2. 状态转移方程
dp[i] = dp[i-1] + dp[i-2] + ...... + dp[i - k] (i - k >= 0)
3. 初始化
dp[0] = 1
4. 填表顺序
从左到右
代码实现
cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n,k;cin>>n>>k;
vector<int> dp(n + 1);
dp[0] = 1;
for(int i = 1;i<=n;i++)
{
for(int j = 1;j<=k && i - j >= 0;j++)
dp[i] = (dp[i] + dp[i - j]) % 100003;
}
cout<<dp[n] % 100003;
return 0;
}
2. 最大子段和
题目链接:

算法原理
方法很多,但本节主要讲的是动态规划,因此我们采用动态规划的方法
1. 状态表示
dp[i]表示前i个元素中,以第i个元素为结尾的最长字段和
2. 状态转移方程
- 如果dp[i-1] >= 0,dp[i] = dp[i-1] + v[i]
- 如果dp[i-1] < 0 ,dp[i] = v[i]
3. 初始化
dp[0] = 0;
4. 填表顺序
从左向右
代码实现
cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int n;cin>>n;
vector<int> v(n + 1);
for(int i = 1;i<=n;i++)
{
int a;cin>>a;
v[i] = a;
}
vector<int> dp(n+1,-0xffffff);
int ret = -0xffffff;
dp[0] = 0;
for(int i = 1;i<=n;i++)
{
if(dp[i-1] >= 0)
dp[i] = dp[i-1] + v[i];
else
dp[i] = v[i];
ret = max(ret,dp[i]);
}
cout<<ret;
return 0;
}
3. 传球游戏
题目链接:

算法原理
1. 状态表示
dp[i][j] 表示传i下球时,到第j个人的方式
2. 状态转移方程
第j个人可以从第j-1和第j+1个人传球
但要注意,j - 1 >= 1并且 j + 1 <= n,这里为了方便,我们将数组下标0表示第1个人
从而 j - 1 >= 0 并且 j + 1 < n
得: dp[i][j] = dp[i - 1][abs(j - 1)] + dp[i - 1][(j + 1) % n];
3. 初始化
一开始,第1个人拿球,即dp[0][0] = 1
4.填表顺序
一定要先循环次数,再循环位置。因为我们更新状态是从低次数更新高次数,也就是第一行更新第二行。因此填表顺序应该是从上往下每一行,行的顺序无所谓。
代码实现
cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n, m; cin >> n >> m;
vector<vector<int>> dp(m + 1, vector<int>(n));
dp[0][0] = 1;
for (int i = 1; i < m + 1; i++)
{
for (int j = 0; j < n; j++)
{
dp[i][j] = dp[i - 1][abs(j - 1)] + dp[i - 1][(j + 1) % n];
}
}
cout << dp[m][0];
return 0;
}