蓝桥杯练习- 2.25

蓝桥杯练习- 2.25

代码练习

Fibonacci数列

解析:

题目中要求得到Fn除以10007的余数是多少,因此我们只要能算出这个余数即可,而不需要先计算出Fn的准确值,再将计算的结果除以10007取余数,直接计算余数往往比先算出原数再取余简单。

我们知道Fibonacci数列的通项公式为
F n = F n − 1 + F n − 2 Fn=Fn-1+Fn-2 Fn=Fn1+Fn2
而这里要求余数,但是先求出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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值