8.31号华为机试
1.字符串压缩(题目较长,代码也长,有时间更新)
给你一句话,然后再给你一个字典,请把这句话中的所有单词替换成该单词在字典中的索引,不区分大小写。句子中包括",."以及空格等符号,这些符号不变,且""之中的单词不会被替换。
例子:
句子:Hello,I will go to the "New World Park".
字典:hEllo TO park
输出:0,I will go 1 the "New World Park".
park在""内,因此不替换。
时间久了,具体代码忘干净了,提供个思路:
1.把字典里面的所有单词都转化为小写(大写)字母单词,并加入到hash表中,
2.分割句子,把句子隔成一个一个的单词,遇到“就跳,一直跳到下一个”停止,
3.每一个分割的单词,转成小写(大写)单词,并在hash表中检索,然后替换
大概五六十行代码
2.士兵走出迷宫:
给你一个迷宫矩阵,从迷宫的左上角走到右下角,请输出最短的通行路径。(给出的迷宫矩阵一定可以走到终点)
其中,值为1时该位置可以走通,值为2时是墙,该位置无法通过,值为3时为陷阱,该位置可以走通,但是要多加三个单位的时间,值为4时,该位置是炸弹,可以走通,而且可以把周围相邻的四堵墙炸开。
例子:
输入:
5 5
1 2 2 3 4
1 2 2 3 4
1 2 2 3 4
1 2 2 3 4
1 1 1 1 1
输出:
(0,0)
(1,0)
(2,0)
(3,0)
(4,0)
(4,1)
(4,2)
(4,3)
(4,4)
题解:
利用dfs+记忆化搜索
代码:(靠记忆回想,有bug,不过总体思路应该差不多,可作为参考)
#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;
int n, m;
int best_step = INT_MAX;;
vector<vector<int>> maze;
vector<pair<int, int>> temp_path;
vector<pair<int, int>> best_path;
void dfs(int i, int j, int cur_step);
int main(void){
//参数输入
cin >> n;
cin >> m;
maze = vector<vector<int>>(n, vector<int>(m));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> maze[i][j];
cout << maze[i][j] << ' ';
}
}
//深度递归遍历+记忆化搜索
dfs(0, 0, 0);
cout << "gello!" << endl;
cout << best_path.empty() << endl;
//输出
for (auto& x : best_path) {
cout << "(" << x.first << "," << x.second << ")" << endl;
}
getchar();
}
void dfs(int i, int j, int cur_step) {
//后面会多次用到节点值,因此取出节点值
int cur = maze[i][j];
//去除非法的道路以及墙
if (i < 0 || j < 0 || i >= n || j >= m || cur == 2) {
return;
}
//找到中点,直接查看结果,此处有一个cur_step和best_step,是因为有陷阱,可能路径最短,但是
if ((i == n - 1) && (j == m - 1)){
if (cur_step < best_step) {
best_path = temp_path;
}
}
//如果此节点为陷阱,则将总步数+3
if (cur == 3) {
cur_step = cur_step + 3;
}
//保存此节点的周围节点值,以防被炸后可以还原
int pre_a;
int pre_s;
int pre_d;
int pre_w;
//此处我忘记题目能不能炸陷阱了,就当能炸,全都设为1
if (cur == 4) {
if (i > 0) {
pre_a = maze[i - 1][j];
maze[i - 1][j] = 1;
}
if (j > 0) {
pre_w = maze[i][j - 1];
maze[i][j - 1] = 1;
}
if (i < n) {
pre_d = maze[i + 1][j];
maze[i + 1][j] = 1;
}
if (j < m) {
pre_s = maze[i][j + 1];
maze[i][j + 1] = 1;
}
}
//对此节点的步数、节点值进行更改,并将该节点加入模拟栈中
cur_step++;
maze[i][j] = 2;
temp_path.push_back({ i, j });
//深度遍历
dfs(i - 1, j, cur_step);
dfs(i + 1, j, cur_step);
dfs(i, j - 1, cur_step);
dfs(i, j + 1, cur_step);
//还原此节点
maze[i][j] = cur;
//将炸了的节点全部还原
if (cur == 4) {
if (i > 0) {
maze[i - 1][j] = pre_a;
}
if (j > 0) {
maze[i][j - 1] = pre_w;
}
if (i < n) {
maze[i + 1][j] = pre_d;
}
if (j < m) {
maze[i][j + 1] = pre_s;
}
}
//出栈
temp_path.pop_back();
} 3.开车到达终点的最短时长。 你有一辆最大1000公里续航的电动车,电动车车速恒定为100公里/小时,即你的车子最多能开10小时。现在,你需要从A地到达B地,中间可能需要多次充电才能到达,这意味着你需要到达充电站进行充电续航。每次充电前需要排队等待,排队时间恒定,排队结束后,充电另需一小时。接下来给你一组数据,第一行第一个数是A、B两地的距离d,第二个数是充电站的总个数m;第二行到接下来的第m+1行,每行都有两个数据,第一个数据为此充电桩距离A始发地的距离,第二个数据为需要排队的等待时间。请你计算出从A地到B地的最短时间。
例子:
输入:
1500 4
300 0
600 1
1000 0
1200 1
输出:
输出:
16(行驶1000公里到达第三个站点,用时10小时,然后充电1小时,继续行驶5小时到达终点,总路程1500公里,总时间10+1+5=16)
题解:
利用动态规划+加回退搜索
把起始点设为0,每次到达一个新的站点,便进行回退搜索,一直搜索到1000公里以内且距离最远的充电站点k,然后从k站点开始遍历,一直遍历到当前站点,找到最短到达当前站点的时间,然后保存到当前站点的时间数组ans中,不断循环遍历,最终遍历到终点。
代码:(靠记忆回想,有bug,不过总体思路应该差不多,可作为参考)
#define DEBUG 1
#if DEBUG
#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(void) {
int n, m;
//参数输入
cin >> n;
cin >> m;
//初始化站点数组,将起点和终点也纳入数组中
vector<vector<int>> f(m+2, vector<int>(2));
//起点的距离和等待时间都设为0
f[0][0] = 0;
f[0][1] = 0;
//终点的距离设为n,等待时间设为0
f[m+1][0] = n;
f[m+1][1] = 0;
//开始加入各个站点
for (int i = 1; i < m+1; i++) {
cin >> f[i][0];
cin >> f[i][1];
cout << f[i][0] << ' ';
cout << f[i][1] << ' ';
}
//初始化到达站点的时间,将起点和终点也纳入数组中
vector<int> ans(m + 2);
ans[0] = 0;
//开始计算各个站点
for (int i = 1; i < m + 2; i++) {
//将所有距离在1000以内的站点找出来
int k = i - 1;
while (k > 0 && (f[i][0] - f[k][0] < 1000)){
k--;
}
//这里除了起始站点以外,多超了一个站点,因此k需要加一
if (k != 0) {
k++;
}
//对每个可以直接到达的站点进行遍历,找出最小的时间站点
int min_time = INT_MAX;
for (; k < i; k++) {
int cur_time = (f[i][0] - f[k][0]) / 100 + ans[k] + f[i][1];
if (k != 0) {
cur_time++;
}
min_time = min(min_time, cur_time);
}
}
getchar();
cout << ans[m+1] << endl;
getchar();
}
#endif // DEBUG
海康威视公司福利 1311人发布