
动态规划判断
① 题目需要求“最值”,可以考虑动态规划
② 有比较明显的状态转移
③ 考虑最优子结构(同时满足重叠子问题是使用DP的必要性)
测试用例给了三组数据,分别表示从站 1 到 2、3的租金,从站 2 到 3的租金
最终花费的最少租金为12,方案为从站 1 到站 2,再从站 2 到站 3(5 + 7 = 12 < 15)
在这里我们发现了状态转移:从站 1 到站 n 的状态,可从站 1 到站 2 到站 3……到站 n,或者站 1 到站 3……到站 n 等的状态转移过来
说得直白一些,我们的方案:
① 直接从站 1 到站 n
② 间接选择几站,然后再到站 n
题目分析
状态是什么?
题目中的变量一般就是状态,因此此题的状态是从站 1 到站 X 的租金数
这个租金也是进行状态转移的对象
如何改变状态?
要改变状态,就要进行一次决策。每一次的决策:是否在站 X 归还游艇(然后再租用游艇到下一站)?
实际操作时,对每一个站点都穷举一遍决策,看看如果归还能不能使得租金少一些
所以每一个站点(除了站 1 以外)就是一个选择,用for循环遍历迭代
DP数组的定义 & 状态转移方程
如果起点没有固定,那么我们可能就需要设定二维DP数组,一个维度表示起点,一个维度表示终点
但这道题固定了起点为站 1,因此只需要一个维度表示终点即可,所以设定DP一维数组
DP[k]表示从站 1 到 站 k 的最少租金
一开始DP[k]数组的值都初始化为r[1][],即从站 1 到各个站 X 的租金
之后考虑每一个选择,也就是每一个站点 X,如果归还了游艇,能否减少租金?
状态转移方程:

很像图论中的Dijkstra算法……(
代码
#include <iostream>
#include <vector>
#include <algorithm>
using std::cin;
using std::cout;
using std::vector;
using std::min;
// 设置一个很大的数
const int INF = 0x3f3f3f3f;
int main() {
int n;
cin >> n;
// r(i, j) 是规定的租金
vector<vector<int>> r(n + 1, vector<int>(n + 1, 0));
vector<int> dp(n + 1);
for (int i = 1; i <= n; ++i) {
for (int j = i + 1; j <= n; ++j) {
cin >> r[i][j];
}
}
// 初始化第一行
for (int i = 2; i <= n; ++i) {
dp[i] = r[1][i];
}
// 动态规划求解
for (int i = 2; i <= n; ++i) {
for (int j = 1; j <= i; ++j) {
dp[i] = min(dp[i], dp[j] + r[j][i]);
}
}
cout << dp[n];
return 0;
}
326

被折叠的 条评论
为什么被折叠?



