蓝桥杯练习- 2.25
代码练习
Fibonacci数列
解析:
题目中要求得到Fn除以10007的余数是多少,因此我们只要能算出这个余数即可,而不需要先计算出Fn的准确值,再将计算的结果除以10007取余数,直接计算余数往往比先算出原数再取余简单。
我们知道Fibonacci数列的通项公式为
F
n
=
F
n
−
1
+
F
n
−
2
Fn=Fn-1+Fn-2
Fn=Fn−1+Fn−2
而这里要求余数,但是先求出Fn再取余,还是算出了Fn的精确值,浪费了时间,所以这里可以用到一个余数定理:
A与B的和除以C的余数,等于A,B分别除以C的余数之和再对C取余
(
A
+
B
)
m
o
d
C
=
(
A
m
o
d
C
+
B
m
o
d
C
)
m
o
d
C
(A+B) mod C = (A mod C + B mod C) mod C
(A+B)modC=(AmodC+BmodC)modC
#include <iostream>
#include <cstdio>
#define N 1000000
using namespace std;
int F[N];
int main()
{
long long int n;
scanf("%lld",&n);
F[1] = F[2] = 1;
for (int i = 3; i <= n; i++)
{
F[i] = (F[i - 1] + F[i - 2]) % 10007;
}
cout << F[n];
return 0;
}
视频练习
视频名称及链接:
2019年蓝桥杯训练营(C++) 11.1 广度优先搜索视频讲解
队列 queue
特点:先进先出,后进后出
队列的主要操作包括:
入队(push)
出队(pop)
判断队列是否为空(empty)
统计队列元素的个数(size)
访问队首元素(front)
C++中 queue 的实现在一个头文件中,在代码开头引入这个头文件
在main函数中直接构造一个 queue 的语句为:queue q,q是队列的名字,x是我们要储存的数据类型
清空
队列没有clear()方法,其实现如下:
while(!q.empty()) {
q.pop();
}
例题-报数游戏
假设有n个小朋友,报到m的小朋友退出游戏,问只剩最后一个小朋友他的编号为?
代码:
#include <iostream>
#include <queue>
using namespace std;
int main()
{
int n, m;
cin >> n >> m;
queue<int> q;
for (int i = 1; i <= n; i++)
{
q.push(i);
}
int cur = 1;//cur表示当前报的数是多少
while (q.size() > 1)//当队列有大于1的人
{
int x = q.front();//每次取队首
q.pop();//把队首拿出来
if (cur == m)//如果当前报到m,其退出游戏
{
cur = 1;//让下一个小朋友从1开始报数
}
else
{
q.push(x);//如果报的不是m,让他到队尾
cur++;
}
}
cout << q.front() << endl;//最后只剩一个数
return 0;
}
广度优先搜索-BFS
BFS会先将起始点距离较近的点搜索完毕,再继续搜索较远的点
BFS需要借助队列来实现:
1.初始的时候把起点放到队列中,并标记起点已经访问过
2.如果队列不为空的,访问队首元素x,否则算法结束
3.访问和x相连的所有点v,如果v没有被访问过,把v放入队列,并标记已经访问过
4.重复执行步骤2
为什么用队列呢,因为当拿出A时,B C D统统都加入了队列尾部
而当拿出B时,访问B周围的点,发现有E和F,这是第一次访问 E F 所以把它们放入队列,但因为是queue,所以是放在最后面,所以B完了之后,取队首是C,之后是D,拿出D的时候,此时队列的排序为E F G,这样就做到了一层一层搜索。
广搜搜出来的结果一般都是最短路径,因为BFS都是一层一层搜索,如果当前x步是终点,x-1步都没有终点,那么x步一定是最短路径。
BFS一般的代码框架
void bfs(起始点) {
将起始点放入队列中;
标记起点访问;
while (如果队列不为空) {
访问队列中队首元素 x;
删除队首元素;
for (x 所有相邻点) {
if (该点未被访问且合法) {
将该点加入队列末尾;
}
}
}
队列为空,广搜结束;
}
BFS例题-迷宫游戏
代码:
#include <iostream>
#include <string>
#include <queue>
using namespace std;
int n, m;
string maze[110];//地图
bool vis[110][110];//判断走的点是否被访问过
int dir[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};//搜索时的方向
bool in(int x, int y)
{
return 0 <= x && x < n && 0 <= y && y < m;//判断每次走过的点是不是再迷宫中
}
struct node //定义一个结构体来记录一个状态,记录坐标 x, y 以及当前使用的步数d
{
int x, y, d;//x,y是当时的位置,d是当时的步数
node(int xx, int yy, int dd)
{
x = xx;
y = yy;
d = dd;
}
};
int bfs(int sx, int sy)//bfs传入俩个参数表示起点的坐标
{
queue<node> q;//定义一个结构体类型的队列
q.push(node(sx, sy, 0));//把起点压入队列
vis[sx][sy] = true;// 并标记起点为访问状态
while (!q.empty())//当队列中有元素的时候
{
node now = q.front();//每一次我们拿出队首的状态,然后队首出去,即访问队首把队首的状态给新建的now
q.pop();//取出队首
for (int i = 0; i < 4; i++)//接下来往四个方向走,这个步骤其实就相当于,搜索当前队首周围一圈
{
int tx = now.x + dir[i][0];
int ty = now.y + dir[i][1];
if (in(tx, ty) && maze[tx][ty] != '*' && !vis[tx][ty])//得先判断在迷宫内
{
if (maze[tx][ty] == 'T')//如果找到了终点T,直接返回当前的步数,该函数即可算出最少步数
{
return now.d + 1;
}
else//否则将该点标记为已经访问过,然后压入队列中(队尾)
{
vis[tx][ty] = true;
q.push(node(tx, ty, now.d + 1));
}
}
}
}
return -1;//如果没找到
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++)
{
cin >> maze[i];
}
int x, y;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (maze[i][j] == 'S')
{
x = i;
y = j;
}
}
}
cout << bfs(x, y) << endl;
return 0;
}