记录82
cpp
#include<bits/stdc++.h>
using namespace std;
int a[210][210], dp[210];
int main(){
int n;
cin>>n;
for(int i=1;i<n;i++){//i为第几段路,j为第几个站点
for(int j=i+1;j<=n;j++) cin >> a[i][j];
}//dp[1]是0,因为目的地1为出发点,不花钱
for(int i=2;i<=n;i++) dp[i]=1e6+10;
for(int i=1;i<n;i++){
for(int j=i+1; j<=n;j++) dp[j]=min(dp[j],dp[i]+a[i][j]);//dp[j]是到j位置最少钱
}//dp[i]是到i最少钱,a[i][j]是在i路段选择到j的钱,i是选择的第几路段,j是其中选择的目的地
cout<<dp[n];
return 0;
}
题目传送门
https://www.luogu.com.cn/problem/P1359
突破口
长江游艇俱乐部在长江上设置了 n 个游艇出租站 1,2,...,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站 i 到游艇出租站 j 之间的租金为 ri,j(1≤i<j≤n)。试设计一个算法,计算出从游艇出租站 1 到游艇出租站 n 所需的最少租金。
思路
📌 题目简述
- 有
n个游艇站:1, 2, ..., n(从上游到下游) - 可以从任意站
i直接租船到下游任意站j(i < j),费用为r[i][j] - 目标:从站 1 到站 n,花费最少租金
💡 注意:可以中途换船!比如 1→3→5,总费用 = r[1][3] + r[3][5]
这本质上是一个 有向无环图(DAG)上的最短路径问题 ,可用 动态规划 高效解决。
✅ 动态规划设计
状态定义:
dp[i]表示 从站点 1 到站点 i 所需的最少租金
初始状态:
dp[1] = 0(起点,不花钱)
状态转移:
- 要到达站点
j,可以从任意上游站点i(i < j)直接租船过来 - 所以:
dp[j]=min1≤i<j(dp[i]+r[i][j])
答案:
dp[n]
代码分析
✅ 代码逐行解释
cpp
#include<bits/stdc++.h>
using namespace std;
int a[210][210], dp[210];
a[i][j]:存储从站i直接到站j的租金(i < j)dp[i]:从站 1 到站i的最小租金- 数组大小 210(因
n ≤ 200,留余量)
cpp
int main(){
int n;
cin >> n;
- 读入站点数
n
🔹 读入租金矩阵(上三角)
cpp
for(int i = 1; i < n; i++){
for(int j = i + 1; j <= n; j++)
cin >> a[i][j];
}
-
输入是 半矩阵 (只给
i < j的值) -
例如
n=3:- 第1行:
a[1][2],a[1][3] - 第2行:
a[2][3]
- 第1行:
-
正好对应样例输入:
cpp3 5 15 → a[1][2]=5, a[1][3]=15 7 → a[2][3]=7
🔹 初始化 DP 数组
cpp
for(int i = 2; i <= n; i++)
dp[i] = 1e6 + 10;
dp[1]默认为 0(全局变量初始化为 0)- 其他
dp[i]设为一个足够大的数(表示"暂时不可达") - 题目提示:任何值 ≤ 1e6,所以
1e6+10是安全的上界
🔹 动态规划递推
cpp
for(int i = 1; i < n; i++){
for(int j = i + 1; j <= n; j++)
dp[j] = min(dp[j], dp[i] + a[i][j]);
}
- 外层
i:枚举当前出发站点 - 内层
j:枚举从 i 能直达的所有下游站点 - 更新:如果通过
i中转到j更便宜,就更新dp[j]
✅ 这正是状态转移方程的实现:
cppdp[j] = min(当前dp[j], 从1到i的最小费用 + i→j的直租费用)
🔹 输出答案
cout << dp[n];
return 0;
}
- 输出从站 1 到站 n 的最小租金
🧪 样例验证(n=3)
输入:
3
5 15
7
即:
a[1][2] = 5,a[1][3] = 15a[2][3] = 7
初始化:
dp[1] = 0dp[2] = dp[3] = 1000010
执行循环:
-
i=1:j=2:dp[2] = min(1000010, 0+5) = 5j=3:dp[3] = min(1000010, 0+15) = 15
-
i=2:j=3:dp[3] = min(15, dp[2]+a[2][3]) = min(15, 5+7) = 12
最终 dp[3] = 12 ✅
最优路径:1 → 2 → 3,费用 5 + 7 = 12,比直接 1→3(15)更优
✅ 总结
| 要点 | 说明 |
|---|---|
| 模型 | DAG 最短路 / 区间 DP 变种 |
| 状态 | dp[i] = 1 到 i 的最小租金 |
| 转移 | 枚举所有可能的上一站 i,更新 dp[j] |
| 复杂度 | O(n²),满足 n≤200 |
| 关键技巧 | 利用"只能往下游走"的性质,按站点顺序递推 |
此代码简洁、高效、正确,解决此类"分段决策最优化"问题的标准 DP 模板