3-6 租用游艇问题(算法设计与分析)

动态规划判断

① 题目需要求“最值”,可以考虑动态规划

② 有比较明显的状态转移

③ 考虑最优子结构(同时满足重叠子问题是使用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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值