文章目录
前言
今天的内容比昨天的稍难一些,今天涉及到了dp问题,本来之前是打算先写一些算法总结的,但是时间不太充裕,就没写,以后我再补上。补不补都是后话了,我们先来看今天的内容。
1. 牛牛的快递
先来一个简单题热热身,做题链接:BC64 牛牛的快递
1.1 题目描述
1.2 解题思路
这道题就是一道简单的模拟题,就根题上说的一步一步写就可以了。可以先不考虑加急不加急,先计算不加急的情况下要花费多少money,再判断是否加急,如果加急,再在结果上加上5个圆子就可以了。
对于不足1kg的按1kg算这一问题,可以用一个整数保存一个浮点数的整数部分,然后再将整数与浮点数进行比较,如果相等,说明它就是一个整数,如果不相等,就说明它是个浮点数,需要在结果加上1kg的费用。
1.3 代码实现
#include <iostream>
using namespace std;
int solve(double n) {
if (n > 1) {
double m = n - 1;
int t = n - 1;
if (m > t) return 20 + t + 1;
else return 20 + t;
}
return 20;
}
int main() {
double a;
char b;
cin >> a >> b;
int ret = solve(a);
if (b == 'y') cout << ret + 5;
else cout << ret;
return 0;
}
2. 最小花费爬楼梯
做题链接:DP4 最小花费爬楼梯
2.1 题目描述
2.2 解题思路
这就是简单的线性dp问题,当你发现要找出结果有很多种情况时,就可以考虑dp解决。
就比如这道题,我们直接抽象出一个具体的例子来看,比如台阶一共有5个,我们从第1个或者第2个台阶出发,一次可以走上1个台阶或者2两个台阶,意味着我们可以到达第3个台阶(1->3或者2->3)或者第4个台阶(2->4),而到达第5个台阶就是3->5或者4->5,到达顶部就是4->顶部或者5->顶部。
我枚举一下:1->3->4->5->顶,1->3->5->顶,2->3->4->5->顶,2->4->5->顶,2->3->5->顶,2->4->顶,等等很多情况,而且你还并不知道每一个台阶的费用,并不是台阶越少花费就越小, 比如2,4台阶每个花费100块,1,3,5台阶每个花费1块,,结果显而易见。
每走一步都有很多中情况(状态)可以选择,这既是dp问题的标志。
我们来看这个题,当遇到第n个台阶时,我们可以选择从第n-1个台阶上来,也可以选择从第n-2个台阶上来, 因此我们可以选择两种方式中花费最小的一种方式上来,也就是我们可以用一个dp[n]来表示:到达第n个台阶所需要的最小花费,它的结果是什么呢?那就是 dp[n] = min(dp[n-1] + cost[n- 1],dp[n-2] + cost[in- 2]),也就是从到达dp[n-1]个台阶和到达dp[n-2]个台阶中,选择小的那一个填到dp[n]。不过比较时还需要加上所走台阶的费用。
大家可以自己用测试用例,通过走读代码的方式来细细体会,因为光用文字描述很难表达(我就是通过走读代码的方式慢慢理解dp问题的,虽然很费力,但是很好用)。
dp问题中,最最重要的是状态表示和状态转移方程,在这个题中状态表示就是:到达第n个台阶所需要花费的最小费用,状态转移方程是:dp[n] = min(dp[n-1] + cost[n- 1],dp[n-2] + cost[in- 2])。
2.3 代码实现
#include <iostream>
using namespace std;
#include <vector>
int main() {
int n = 0;
cin >> n;
vector<int> cost(n + 1, 0);
for (int i = 0; i < n; i++) cin >> cost[i];
vector<int> dp(n + 1);
dp[0] = dp[1] = 0;
for (int i = 2; i <= n; i++)
{
dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
}
cout << dp[n];
return 0;
}
3. 数组中两个字符串的最小距离
做题链接:数组中两个字符串的最小距离
3.1 题目描述
3.2 解题思路
这道题是要求时间复杂度为O(n),空间复杂度为O(1),也就是说我们只能循环一次,并在在原地上进行解决问题。
可以使用两个指针cur1和cur2,一个标记str1,一个标记str2,每遇到新的str1或者str2,并且当前cur 的值合法的,都对最后的结果进行更新,然后再将cur也进行更新。
3.3 代码实现
#include <iostream>
using namespace std;
#include <string>
int main() {
int n = 0;
cin >> n;
string str1, str2, s;
cin >> str1 >> str2;
int cur1 = -1, cur2 = -1, ret = 0x3f3f3f3f;
for (int i = 0; i < n; i++) {
cin >> s;
if (s == str1)
{ // 去前⾯找最近的 s2
if (cur2 != -1)
{
ret = min(ret, i - cur2);
}
cur1 = i;
}
else if (s == str2)
{ // 去前⾯找 s1
if (cur1 != -1)
{
ret = min(ret, i - cur1);
}
cur2 = i;
}
}
if (ret == 0x3f3f3f3f) cout << -1;
else cout << ret;
return 0;
}
总结
今天的比昨天的难度增加了一些,但是也还好,主要是dp问题,如果看不懂题解的话,可以先走读代码顺一遍过程,再来看题解,相信你会有新的理解。
那么第二天的内容就到此结束了,希望自己可以继续坚持下去,也希望能与大家共同进步,如果大家发现有什么错误的地方,可以私信或者评论区指出喔。我会继续坚持训练的,共勉!!!那么本期就到此结束,让我们下期再见!!觉得不错可以点个赞以示鼓励!!