目录

  • 7-1 输出全排列(C++,DFS)
    • 题目描述:
    • 输入格式:
    • 输出格式:
    • 输入样例:
    • 输出样例:
    • 解题思路:
  • 7-2 山(C++,BFS)
    • 题目描述:
    • 要求:
    • 示例:
    • 范围:
    • 解题思路:
  • 7-3 跳跃(C++,DFS)
    • 题目描述:
    • 要求:
    • 示例:
    • 范围:
    • 解题思路:
  • 7-4 最长光路(C++,DFS)
    • 题目描述:
    • 注意
    • 输入格式:
    • 输出格式:
    • 输入样例1:
    • 输出样例1:
    • 输入样例2:
    • 输出样例2
    • 样例解释
    • 解题思路:
  • 7-5 回文数文回
    • 题目描述:
    • 输入格式:
    • 输出格式:
    • 输入样例:
    • 输出样例:
    • 解题思路:

7-1 输出全排列(C++,DFS)

题目描述:

请编写程序输出前n个正整数的全排列(n<10),并通过9个测试用例(即n从1到9)观察n逐步增大时程序的运行时间。

输入格式:

输入给出正整数n(<10)。

输出格式:

输出1到n的全排列。每种排列占一行,数字间无空格。排列的输出顺序为字典序,即序列a1,a2,⋯,ana_1,a_2,⋯,a_na1​,a2​,⋯,an​排在序列b1b_1b1​,b2b_2b2​,⋯,bnb_nbn​之前,如果存在k使得a1=b1,⋯,ak=bka_1=b_1,⋯,a_k=b_ka1​=b1​,⋯,ak​=bk​ 并且 ak+1<bk+1a_k+1<b_k+1ak​+1<bk​+1。

输入样例:

3

输出样例:

123
132
213
231
312
321

解题思路:

注意题目要求从小到大输出n位数字的全排列,那么我们尝试的时候就要按1~9的顺序

全排列问题采用DFS即可

以下是实现代码

#include <iostream>
using namespace std;int num_array[10] = { 0 };
bool book[10] = { 0 };
int n;void dfs(int now) {//now代表当前是左数第几位,n为总位数//递归停止条件if (now == n + 1) {for (int i = 1; i <= n; i++) {putchar('0' + num_array[i]);}putchar('\n');return;}//递归主体for (int i = 1; i <= n; i++) {//尝试1~nif (!(book[i])) {num_array[now] = i;book[i] = true;dfs(now + 1);book[i] = false;}}
}int main() {cin >> n;dfs(1);return 0;
}

如果有不明白DFS是如何实现全排列的可以接着阅读

找到n位数的全排列本质就是枚举从[10n,10n+1−110^n, 10^{n+1}-110n,10n+1−1]的所有数字

可以用n层的for循环来实现,但是for循环的层数是需要随着输入的变化而变化的,故可以采用递归实现

void dfs(int now) {//递归停止条件if (now == n + 1) {;//判断是否是全排列;//输出找到的全排列return;}//递归主体for (int i = 1; i <= n; i++) {//枚举1~ndfs(i);}
}

可以看到,这个算法的时间复杂度是o(nnn^nnn),那么我们需要进行优化

先说明一个简单的情形:如果第一个数字是1,当第二个数字也是1的时候,就可以停止尝试,也就是常说的剪枝

根据这个思路进行优化

bool book[10] = { false };//标记出现过的数字void dfs(int now) {//递归停止条件if (now == n + 1) {//一定是一种全排列,不需要再判断;//输出找到的全排列return;}//递归主体for (int i = 1; i <= n; i++) {//枚举1~nif (!(book[i])) {//如果i没出现过book[i] = true;//标记idfs(i);book[i] = false;//不要忘记取消标记}}
}

至此,对DFS如何实现全排列的解释完成

7-2 山(C++,BFS)

题目描述:

Drizzle 前往山地统计大山的数目,现在收到这片区域的地图,地图中用0(平地)1(山峰)绘制而成,请你帮忙计算其中的大山数目
山总是被平地四面包围着,每一座山只能在水平或垂直方向上连接相邻的山峰而形成。一座山峰四面被平地包围,这个山峰也算一个大山
另外,你可以假设地图的四面都被平地包围着。

要求:

输入:第一行输入M,N分别表示地图的行列,接下来M行每行输入N个数字表示地图
输出:输出一个整数表示大山的数目

示例:

输入:

4 5
1 1 0 0 0
1 1 0 0 0
0 0 1 0 0
0 0 0 1 1

输出:

3

范围:

对于 5% 的数据:M,N ≤ 10
对于 100% 的数据:M,N ≤ 2000

解题思路:

读完题第一反应就是正面求解,也就是去寻找山的边界,然后就会发现这个思路不太可行

那么换一个思路,现在由于全球变暖导致海平面升高,平地变成了海,而山变成了平地,我们是不能在海面上走的,所以我们只能在山上走,那么我们每次都走完一座山的每一个角落,然后去找下一座山

进一步解释一下,我们已经知道的是哪个格子代表山,我们如果还能知道哪些格子已经走过,我们就能确定山的数目了

如果还不明白,可以理解为染色,我们把第一次到达的山染上"1"的颜色,第二次到达的山染上“2”的颜色……然后我们就可以知道有几座山了

实现代码如下

#include <iostream>
#include <queue>
using namespace std;const int max_m_n = 2000;struct position {int m_x;int m_y;
};int M, N;
int map[max_m_n][max_m_n] = { 0 };//地图
bool book[max_m_n][max_m_n] = { false };//地图标记
queue<position> bfs_queue;
int step[4][2] = {//按右、下、左、上的顺序尝试{0, 1},{1, 0},{0, -1},{-1, 0}
};void bfs(int x, int y) {//初始化struct position temp_pos;temp_pos.m_x = x, temp_pos.m_y = y;bfs_queue.push(temp_pos);//队列初始化book[x][y] = true;//标记//bfs主体while (!(bfs_queue.empty())) {for (int i = 0; i < 4; i++) {//尝试四个方向temp_pos.m_x = bfs_queue.front().m_x + step[i][0];temp_pos.m_y = bfs_queue.front().m_y + step[i][1];if (temp_pos.m_x < 0 || temp_pos.m_x >= M || temp_pos.m_y < 0 || temp_pos.m_y >= N)//越界continue;if (book[temp_pos.m_x][temp_pos.m_y])//访问过continue;if (!(map[temp_pos.m_x][temp_pos.m_y]))//平地continue;bfs_queue.push(temp_pos);book[temp_pos.m_x][temp_pos.m_y] = true;//标记}bfs_queue.pop();//队首尝试完毕,出队}
}int main() {int sum = 0;cin >> M >> N;for (int i = 0; i < M; i++) {//输入地图for (int j = 0; j < N; j++) {cin >> map[i][j];}}//统计山的数目for (int i = 0; i < M; i++) {for (int j = 0; j < N; j++) {if (!(book[i][j]) && map[i][j]) {//未访问 && 是山bfs(i, j);sum++;}}}cout << sum;return 0;
}

7-3 跳跃(C++,DFS)

题目描述:

Drizzle 被困到一条充满数字的方块路中,假设这条路由一个非负的整数数组m组成,Drizzle 最开始的位置在下标 start 处,当他位于下标i位置时可以向前或者向后跳跃m[i]步数,已知元素值为0处的位置是出口,且只能通过出口出去,不可能数组越界,请你通过编程计算出Drizzle能否逃出这里。

要求:

输入:第一行输入数组m的长度n 第二行输入数组元素,空格分割开 第三行输入起始下标start

示例:

输入:

7
4 2 3 0 3 1 2
5

输出:

True

范围:

  • 1≤m.length≤5∗1041 \leq m.length \leq 5 * 10^41≤m.length≤5∗104
  • 0≤m[i]<m.length0 \leq m[i] < m.length0≤m[i]<m.length
  • 0≤start<m.length0 \leq start < m.length0≤start<m.length

解题思路:

题意可以理解为搜索路径,故用DFS来实现

好像很简单,但是我们实现过程中会发现问题:如何递归

考虑一下我们来到一个格子后有几种情况:

(1)已经走过

(2)未走过:未走过又可以分为两种情况:<1>找到出口 <2>未找到

继续思考,我们每来到一个格子需要进行两次判断,那么有如下几种情况

(1)两侧均已经走过

(2)至少有一侧未走过

所有情况都考虑完毕了,现在我们知道dfs结束条件只有两个

(1)两侧均已经走过

(2)找到出口

第一种情况返回0,第二种情况返回1即可

完整的实现代码如下

#include <iostream>
using namespace std;int n;
int num_array[500] = { 0 };
bool book[500] = { false };//标记,注意本题dfs无需取消标记,可以自行思考为什么bool dfs(int now) {//now为当前格子的索引if (num_array[now] == 0)//找到出口return 1;if (now + num_array[now] < n && !(book[now + num_array[now]])) {//未越界 && 未走过book[now + num_array[now]] = true;//标记if (dfs(now + num_array[now]))return 1;//找到出口,连续返回,不需要继续尝试}if (now - num_array[now] >= 0 && !(book[now - num_array[now]])) {//未越界 && 未走过book[now - num_array[now]] = true;//标记if (dfs(now - num_array[now]))return 1;//找到出口,连续返回,不需要继续尝试}return 0;//两侧均走过
}int main() {int start;cin >> n;for (int i = 0; i < n; i++)//读入数组cin >> num_array[i];cin >> start;//读入起始索引if(dfs(start))cout << "True";elsecout << "False";return 0;
}

7-4 最长光路(C++,DFS)

题目描述:

小明在做丁达尔效应的实验。
他用胶体填满了一个有 N 行, M 列个格子的透明盒子。同时,为了使实验效果更好,他在盒子的某些格子中装入一些双面镜(用“/”和“\”表示)。
当光线找到双面镜的时候,光路会反射,方向会有90度的转换(如下图所示)。

小明在填充胶体的时候产生了失误,使得有些格子光线无法穿过(我们可以认为这些格子把光线都吸收了),这些格子用大写字母“C”来表示。

现在,小明已经制作好了实验装置,他将激光光源放在第sxs_xsx​行的第sys_ysy​个格子上。激光光源可以朝向上下左右四个方向,分别用URDL四个字母表示(“U”-上, “R”-右, “D”-下, “L”-左)。

为了让实验效果更好,小明希望光的光路越酷越好。
对小明来说,最酷的光路就是包含环的光路,这种情况下,光不会射向盒子外面,而是一直在盒子内循环(数据保证光源处的点是光线可以通过,即起点一点是".")。
如果光源朝各个方向摆设,最终光线都会射向盒子外部,那么小明认为经过格子最多的光路是最酷的。

现在小明想知道光源朝哪个方向放置光路最酷。
如果光路是不包含环的,那么他还想知道光路经过的格子数目是多少。

注意

如果有多个方向是最优解,那么我们按照“U”-上, “R”-右, “D”-下, “L”-左的优先级来选择最终的答案,即如果向左和向右都是最优解,我们选择向右的方案。

同时,温馨提醒,c++中“\”符号可以用'\\'来表示

输入格式:

第一行两个数 N,M(1≤N,M≤500) 表示有NM 列的格子。
接下来 N 行, 每行 M 个字符,表示盒子的具体情况。 “/”和“\”表示装有不同朝向的镜子的格子。“C”表示光线无法通过的格子。“.”表示正常且没有镜子的格子。
最后输入两个数字sx,sys_x,s_ysx​,sy​表示光源所在的点。

输出格式:

第一行输出一个大写字母,表示最酷的光路应该超哪个方向摆放。
第二行输出光路经过的格子数。如果光路中包含环,则换成输出字符串“COOL”。

输入样例1:

5 5
../.\
.....
.C...
...C.
\.../
3 3

输出样例1:

U
17

输入样例2:

5 7
/.....\
../..\.
\...../
/.....\
\.\.../
3 3

输出样例2

R
COOL

样例解释

S为起点
../.\
.....
.CS..
...C.
\.../'U' 方向
*.***
*.*.*
*C*.*
*..C*
*****
17个格子'R'方向
../.\
.....
.C***
...C.
\.../
3个格子'D'方向
../.\
.....
.C*..
..*C.
\.*./
3个格子'L'方向
../.\
.....
.C*..
...C.
\.../
1个格子

解题思路:

(1)光的传播方向:

我们把光定义出四种状态:向上/右/下/左传播

地图上的双面镜有两种状态:‘\\‘和’/’

我们可以根据这两种状态对光的传播方向进行改变

(2)闭环判断:

充分必要条件是再次回到起点,且传播方向与初始状态相同

(3)DFS终止条件:

<1>越界

<2>闭环

<3>被吸收(‘C’)

此外,由于DFS无返回后操作,可以用while循环实现

实现DFS的大致思路:光传播一格,然后进行判断

代码实现如下

#include <iostream>
using namespace std;int toward[4][2] = {//上、右、下、左{-1, 0},{0, 1},{1, 0},{0, -1}
};
string map[500];int main() {int N, M, start_x, start_y, max_sum = 0, max_light = 0;cin >> N >> M;for (int i = 0; i < N; i++)cin >> map[i];cin >> start_x >> start_y;for (int i = 0; i < 4; i++) {//尝试四个方向int light = i, cur_x = start_x - 1, cur_y = start_y - 1, sum = 1;//注意:修改起始下标,并且起点也算格子while (true) {cur_x += toward[light][0];cur_y += toward[light][1];sum++;if (cur_x == start_x - 1 && cur_y == start_y - 1 && light == i) {//COOL!switch (i){case 0:putchar('U');break;case 1:putchar('R');break;case 2:putchar('D');break;case 3:putchar('L');break;default:break;}putchar('\n');cout << "COOL";return 0;}if (cur_x < 0 || cur_x >= N || cur_y < 0 || cur_y >= M) {//出界sum--;break;}else if (map[cur_x][cur_y] == '.')//正常传播continue;else if (map[cur_x][cur_y] == 'C') {//吸收sum--;break;}else if (map[cur_x][cur_y] == '\\') {switch (light)//改变传播方向{case 0://光向上传播light = 3;//转向左break;case 1://光向右传播light = 2;//转向下break;case 2://光向下传播light = 1;//转向右break;case 3://光向左传播light = 0;//转向上break;default:break;}}else if (map[cur_x][cur_y] == '/') {switch (light)//改变传播方向{case 0://光向上传播light = 1;//转向右break;case 1://光向右传播light = 0;//转向上break;case 2://光向下传播light = 3;//转向左break;case 3://光向左传播light = 2;//转向下break;default:break;}}}//尝试结束if (max_sum < sum) {max_sum = sum;max_light = i;}}switch (max_light){case 0:putchar('U');break;case 1:putchar('R');break;case 2:putchar('D');break;case 3:putchar('L');break;default:break;}putchar('\n');cout << max_sum;return 0;
}

7-5 回文数文回

题目描述:

我们称一个数是回文的,当且仅当它正着读和倒着读是相同的。

例如11或11455411是回文的,而10或1919810不是回文的。

现在给定一个数n,你需要求出区间[10810^8108,n]中所有的回文数。

输入格式:

一行一个整数n(108≤n<10910^8≤n<10^9108≤n<109)

输出格式:

输出一行一个数,表示题目所求区间中回文数的数量。

输入样例:

在这里给出一组输入。例如:

100000001

输出样例:

在这里给出相应的输出。例如:

1

解题思路:

题中给出了回文数的固定长度为9,由于回文数是对称的,我们只需要考虑前5个符号的序列即可

将前5个符号看做一个整数,每一个整数都对应着一个序列

如果输入的n是2345671991的话,在前五个数=23456之前,不可能有大于n的整数

那么我们只需要判断234565432是否符合题意即可

如果我们采用如下的方式

while(left < right) {if (str[left] > str[right]) {sum--;break;}left++, right--;//从两侧向中间
}

很快就会发现问题,按这个判断算法,234565432是不符合题意的

那么我们修改一下

while(left >= 0 && right <= 8) {if (str[left] > str[right]) {sum--;break;}left--, right++;//从中间向两侧
}

显然,234565432仍然不符合题意,因为4 > 1

我们会发现,不能单独看每一个符号,因为它们是一个整数

所以正确的判断算法如下

reverse(&str[0], &str[0] + 4);
stoi(str.substr(0, 4)) > stoi(str.substr(5, 9)) ? int_n-- : int_n;

注意只能反转前4位,可以想一想为什么反转前5位会出现问题

本题完整的实现代码如下

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;int main() {string n;int int_n;cin >> n;int_n = stoi(n.substr(0, 5));reverse(&n[0], &n[0] + 4);stoi(n.substr(0, 4)) > stoi(n.substr(5, 9)) ? int_n-- : int_n;cout << int_n - 1e4 + 1;return 0;
}

NEUQACM双周赛(二)相关推荐

  1. NEUQACM双周赛(三)

    目录 7-1 打字(C++) 题目描述: 输入格式: 输出格式: 输入样例1: 输出样例1: 输入样例2: 输出样例2: 解题思路: 7-2 分香肠(C++,最大公约数) 题目描述: 输入格式: 输出 ...

  2. 20201023:力扣第37场双周赛(上)

    力扣第37场双周赛(上) 题目 思路与算法 代码实现 写在最后 题目 删除某些元素后的数组均值 网络信号最好的坐标 思路与算法 第二题直接暴力就可以了,计算每个点的所有偏移量存入list,即以(0,0 ...

  3. 20200827:2020力扣第33周双周赛题解

    2020力扣第33周双周赛题解 题目一 示例 解题思路与代码实现 题目二 示例 解题思路与代码实现 题目三 解题思路与代码实现 题目四 示例 解题思路与代码实现 写在最后 题目一 题目一:千位分隔数 ...

  4. 20200727:力扣第31周双周赛题解

    力扣第31周双周赛题解 题目一:在区间范围内统计奇数数目 给你两个非负整数low和high,请你返回low和high之间(包含二者)奇数的数目 0 <= low <= high <= ...

  5. C#实现力扣双周赛算法题:以组为单位订音乐会的门票订购

    目录: 前言: 一,算法题目描述 二,基本概念理解: 三,例子引入分析 四,代码解释 (1)安排座位函数 (2)查询函数 (2)求出1到RPS内的最小下标 (3)gather函数 (4)scatter ...

  6. LeetCode第 57 场力扣夜喵双周赛(差分数组、单调栈) and 第 251 场力扣周赛(状态压缩动规,树的序列化,树哈希,字典树)

    LeetCode第 57 场力扣夜喵双周赛 离knight勋章越来越近,不过水平没有丝毫涨进 1941. 检查是否所有字符出现次数相同 题目描述 给你一个字符串 s ,如果 s 是一个 好 字符串,请 ...

  7. LeetCode 第 59 场力扣夜喵双周赛(最短路径数+迪杰斯特拉、动态规划+最长公共前缀问题) / 第255场周赛(二进制转换,分组背包,子集还原数组(脑筋急转弯))

    第 59 场力扣夜喵双周赛 两道400多五百,后两道都写出代码来了,但是都有问题,哭辽- 还有刚开始第一道测试好慢,搞心态了 5834. 使用特殊打字机键入单词的最少时间 有一个特殊打字机,它由一个 ...

  8. [LeetCode周赛复盘] 第 89 场双周赛20221015

    [LeetCode周赛复盘] 第 89 场双周赛20221015 一.本周周赛总结 二. [Easy] 6208. 有效时间的数目 1. 题目描述 2. 思路分析 3. 代码实现 三.[Medium] ...

  9. Leetcode周赛复盘——第 71 场力扣双周赛与第 279 场力扣周赛

    双周赛: 5984. 拆分数位后四位数字的最小和 class Solution:def minimumSum(self, num: int) -> int:a, b, c, d = sorted ...

最新文章

  1. 回归 统计绘图_手把手教绘制回归分析结果的森林图「GraphPad Prism和Excel」
  2. Flutter开发之Stack组件(层叠布局)(19)
  3. python基础学习[python编程从入门到实践读书笔记(连载三)]:django学习笔记web项目
  4. cmd下的一些小技巧
  5. OpenGL之控制渲染图形的移动
  6. 使用vim打开文件的16进制形式,编辑和全文替换
  7. 网络安全课程学习内容
  8. (计算机组成原理)第二章数据的表示和运算-第二节6:定点数除法运算(原码/补码一位除法)
  9. Daemon线程--《Java并发编程的艺术》学习笔记
  10. git规则写法_3条简单的规则将帮助您成为Git大师
  11. Lethean结点搭建
  12. 施密特:乔布斯影响力还没有完全释放
  13. FFmpeg音视频同步的问题
  14. 【优化电价】基于matlab遗传算法求解共享汽车电价优化问题【含Matlab源码 1162期】
  15. api arx autocad_应用ARX实现基于AutoCAD平台的参数化绘图
  16. 基于VGG19的图片分割网络
  17. edem颗粒替换_EDEM离散元软件中颗粒替换与填充编程模版
  18. m3u8格式转换器android,m3u8转换格式mp4软件下载-m3u8转换格式 安卓版v2.7.0-PC6安卓网...
  19. vue改变class名字_vue添加class类名
  20. ffmpeg命令下载MP4视频)

热门文章

  1. Games104现代游戏引擎入门-lecture4游戏中的渲染系统
  2. 交换机接口类型Access和Trunk详解
  3. 3A Cloud 思维导图 for Mac(思维导图软件)中文版
  4. makefile中的wildcard 、patsubst、
  5. 初中生计算机考试实施方案,2021 年德阳市初中毕业生信息技术学业水平考试实施方案,精英中考网...
  6. 修炼内功---数据结构与算法6---队列
  7. 解决npm安装bootstrap 4 报错问题
  8. h5页面生成图片分享到微信js_H5微信自定义分享链接(设置标题+简介+图片)
  9. changyan main.php,zblog畅言插件不能用,代码实现安装畅言评论zblog主题安装畅言评论代码...
  10. 20172266遥感一班李安娜第二次笔记