蓝桥杯练习-3.7
代码练习
▪ FJ的字符串
问题描述
最近FJ为他的奶牛们开设了数学分析课,FJ知道若要学好这门课,必须有一个好的三角函数基本功。所以他准备和奶牛们做一个“Sine之舞”的游戏,寓教于乐,提高奶牛们的计算能力。
不妨设
An=sin(1–sin(2+sin(3–sin(4+…sin(n))…)
Sn=(…(A1+n)A2+n-1)A3+…+2)An+1
FJ想让奶牛们计算Sn的值,请你帮助FJ打印出Sn的完整表达式,以方便奶牛们做题。
输入格式
仅有一个数:N<201。
输出格式
请输出相应的表达式Sn,以一个换行符结束。输出中不得含有多余的空格或换行、回车符。
样例输入
3
样例输出
((sin(1)+3)sin(1–sin(2))+2)sin(1–sin(2+sin(3)))+1
思路:
找规律,注意表达式的通项和主体部分,做到不重不漏。
注意到An = sin(n ± sin(n + 1)),A1 = sin(1 - sin(2)),A2 = sin(2 + sin(3))
#include <iostream>
#include <cstdio>
using namespace std;
void An(int x, int N);
void Sn(int N, int t)//其中N代表输入的n,t则代表的是加的数
{
if (N > 1)
{
printf("(");
Sn(N - 1, t + 1);
}
An(1, N);
printf("+");
printf("%d", t);
if(t != 1)
printf(")");
}
void An(int x, int N)
{
if (x == N)
{
printf("sin(%d)",N);
return;
}
printf("sin(");//注意表达式主体部分,有括号一定有括回
if (x < N)
{
if (x % 2 == 0)
printf("%d+",x);
else printf("%d-",x);
An(x + 1, N);
}
printf(")");//括回
}
int main()
{
int n;
cin >> n;
Sn(n, 1);
return 0;
}
▪ 芯片测试
问题描述
有n(2≤n≤20)块芯片,有好有坏,已知好芯片比坏芯片多。
每个芯片都能用来测试其他芯片。用好芯片测试其他芯片时,能正确给出被测试芯片是好还是坏。而用坏芯片测试其他芯片时,会随机给出好或是坏的测试结果(即此结果与被测试芯片实际的好坏无关)。
给出所有芯片的测试结果,问哪些芯片是好芯片。
输入格式
输入数据第一行为一个整数n,表示芯片个数。
第二行到第n+1行为n*n的一张表,每行n个数据。表中的每个数据为0或1,在这n行中的第i行第j列(1≤i, j≤n)的数据表示用第i块芯片测试第j块芯片时得到的测试结果,1表示好,0表示坏,i=j时一律为1(并不表示该芯片对本身的测试结果。芯片不能对本身进行测试)。
输出格式
按从小到大的顺序输出所有好芯片的编号
样例输入
3
1 0 1
0 1 0
1 0 1
样例输出
1 3
思路:因为,题目中说到好芯片的数量比坏芯片的数量多,因此只要判断每一个芯片的合格次数大于n/2即可。
代码实现:
#include <iostream>
using namespace std;
int n;
int a[25][25];
int num[25];
int main()
{
cin >> n;
for (int i = 1; i <= n ; ++i)
{
for (int j = 1; j <= n; ++j)
{
cin >> a[i][j];
if (a[i][j] == 1)
num[j]++;
}
}
for (int i = 0; i <= n ; ++i)
{
if (num[i] > n / 2)
cout << i << " ";
}
return 0;
}
▪ C 数列求和(第十届蓝桥杯)
Description
给定数列 1, 1, 1, 3, 5, 9, 17, …,从第 4 项开始,每项都是前 3 项的和。
求第 20190324 项的最后 4 位数字。
Input
没有输入。
Output
这是一道结果填空的题,你只需要算出结果后提交即可。
本题的结果为一个 4 位整数(提示:答案的千位不为 0),
思路
跟斐波那契数列类似,注意的是,最后只需要要后四位的值,所以我们在每一次加完前三项的和以后,让和对10000取余这样最后得出的结果就是最后4位数字
答案:4659
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int a, b, c;
a = b = c = 1;
int d;
for (int i = 4; i <= 20190324; i++)
{
d = a + b + c;
d %= 10000;
a = b;
b = c;
c = d;
}
cout << d << endl;
return 0;
}
▪ D 数的分解(第十届蓝桥杯)
Description
把 2019 分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包含数字 2 和 4,一共有多少种不同的分解方法?
注意交换 3 个整数的顺序被视为同一种方法,例如 1000+1001+18 和1001+1000+18 被视为同一种。
Input
没有输入。
Output
这是一道结果填空的题,你只需要算出结果后提交即可
思路
直接暴力点用三个for循环,出结果的时候可能要等几秒,然后就是注意不能包含2和4,以及三个整数的顺序被视为一个,我们可以在i循环的基础上j从i+1开始循环,k从j+1开始循环,这样可以避免掉他们是各不相同,而且结果不重复,即结果都是三个数依次递增,或者算出所有结果,最后除6,也就是3的全排列数也行
代码实现
#include <iostream>
using namespace std;
int ans = 0;
int judge(int n)
{
int flag = 1;
while(n)
{
if (n % 10 == 2 || n % 10 == 4)
{
flag = 0;
}
n /= 10;
}
return flag;
}
int main()
{
for (int i = 1; i <= 2019; ++i)
{
for (int j = i + 1; j <= 2019; ++j)
{
for (int k = j + 1; k <= 2019; ++k)
{
if (i + j + k == 2019)
{
if (judge(i) == 1 && judge(j) == 1 && judge(k) == 1)
ans++;
}
}
}
}
cout << ans << endl;
return 0;
}
▪ E 迷宫(第十届蓝桥杯)
Description
下图给出了一个迷宫的平面图,其中标记为 1 的为障碍,标记为 0 的为可
以通行的地方。
010000
000100
001001
110000
迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这个它的上、下、左、右四个方向之一。
对于上面的迷宫,从入口开始,可以按DRRURRDDDR 的顺序通过迷宫,
一共 10 步。其中 D、U、L、R 分别表示向下、向上、向左、向右走。
对于下面这个更复杂的迷宫(30 行 50 列),请找出一种通过迷宫的方式,
其使用的步数最少,在步数最少的前提下,请找出字典序最小的一个作为答案。
请注意在字典序中D<L<R<U。(如果你把以下文字复制到文本文件中,请务
必检查复制的内容是否与文档中的一致。在试题目录下有一个文件 maze.txt,
思路
使用BFS-广度优先搜索,在BFS的基础上,我们将bfs搜索函数的类型设为string,以便我们最后输出 D、U、L、R,记得结构体内,需要有一个string类型的变量,来得到路径,它是一直叠加的,最终会得到一长串路径。
❕注意:判断最后到达终点的if语句可以放在俩个地方,① 一个地方是直接在拿出队首状态的下一句,如果是终点,直接返回现在结构体中的路径数,注意这里是不用加d[i]的,因为我们上一次while循环已经加好了,只是放在下一个循环判断。② 另一个地方是在for循环的if语句里面,也就是走到下一步之后立即判断,这里就需要返回now.d + d[i]了,因为还没加上这一步的路径
还有就是dir[4] [2]数组一定要书写准确!!!不然最后的结果都得不出来
代码实现:
#include <iostream>
#include <string>
#include <queue>
using namespace std;
string maze[100];//地图
bool vis[50][60];//标记
int dir[4][2] = {{1, 0}, {0, -1}, {0, 1}, {-1, 0}};//分别对应着下面的,可以保证优先是按下面那种顺序寻找的
char d[] = {'D','L','R','U'};
bool in(int x, int y)
{
return 0 <= x && x < 30 && 0 <= y && y < 50;
}
struct node
{
int x, y;
string d;//标记路径
};
string bfs()
{
queue<node> q;//定义一个结构体类型的队列
node p;
p.x = 0;
p.y = 0;
p.d = "";
vis[0][0] = true;//标记已经走过
q.push(p);//将开头的元素压入队列中
while (!q.empty())//当队列中有元素的时候
{
node now = q.front();//每一次我们拿出队首的状态,然后队首出去,即访问队首把队首的状态给新建的now
if (now.x == 29 && now.y == 49)
return now.d;
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] != '1' && !vis[tx][ty])
{
vis[tx][ty] = true;
node next;
next.x = tx;
next.y = ty;
next.d = now.d + d[i];//标记我们走过的路径
q.push(next);
}
}
}
return "";
}
int main()
{
for (int i = 0; i < 30; i++)
{
cin >> maze[i];
}
string str = bfs();
cout << str << endl;
return 0;
}
▪ F 特别数的和(第十届蓝桥杯)
Description
小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导 0),
在 1 到40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。
请问,在 1 到 n 中,所有这样的数的和是多少?
Input
输入一行包含一个整数 n。
Output
输出一行,包含一个整数,表示满足条件的数的和。
思路:这题挺简单的,就是平常的做法,输入的n值也不是很大,写一个judge函数判断数是否含有2、0、1、9等数字,有的话就累加到sum中即可
代码实现
#include <iostream>
using namespace std;
int judge(int x)
{
int flag = 0;
while(x)
{
int t = x % 10;
if (t == 2 || t == 0 || t == 1 || t == 9)
{
flag = 1;
}
x /= 10;
}
return flag;
}
int main()
{
int n;
int sum = 0;
cin >> n;
for (int i = 1; i <= n; i++)
{
if (judge(i))
sum += i;
}
cout << sum << endl;
return 0;
}
视频学习
也引用了这篇博客
1 重点概念
1.1 结点概念
结点是数据结构中的基础,是构成复杂数据结构的基本组成单位。
1.2 树结点声明
本系列文章中提及的结点专指树的结点。例如:结点A在图中表示为:
2 树
2.1 定义
**树(Tree)**是n(n>=0)个结点的有限集。n=0时称为空树。在任意一颗非空树中:
1)有且仅有一个特定的称为根(Root)的结点;
2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1、T2、…、Tn,其中每一个集合本身又是一棵树,并且称为根的子树。
此外,树的定义还需要强调以下两点:
1)n>0时根结点是唯一的,不可能存在多个根结点,数据结构中的树只能有一个根结点。
2)m>0时,子树的个数没有限制,但它们一定是互不相交的。
示例树:
图2.1为一棵普通的树:
图2.1 普通树
由树的定义可以看出,树的定义使用了递归的方式。递归在树的学习过程中起着重要作用,如果对于递归不是十分了解,建议先看看递归算法
2.2 结点的度
结点拥有的子树数目称为结点的度。
图2.2中标注了图2.1所示树的各个结点的度。
图2.2 度示意图
2.3 结点关系
结点子树的根结点为该结点的孩子结点。相应该结点称为孩子结点的双亲结点。
图2.2中,A为B的双亲结点,B为A的孩子结点。
同一个双亲结点的孩子结点之间互称兄弟结点。
图2.2中,结点B与结点C互为兄弟结点。
2.4 结点层次
从根开始定义起,根为第一层,根的孩子为第二层,以此类推。
图2.3表示了图2.1所示树的层次关系
图2.3 层示意图
2.5 树的深度
树中结点的最大层次数称为树的深度或高度。图2.1所示树的深度为4。
3 二叉树
3.1 定义
二叉树是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树组成。
图3.1展示了一棵普通二叉树:
3.2 二叉树特点
由二叉树定义以及图示分析得出二叉树有以下特点:
1)每个结点最多有两颗子树,所以二叉树中不存在度大于2的结点。
2)左子树和右子树是有顺序的,次序不能任意颠倒。
3)即使树中某结点只有一棵子树,也要区分它是左子树还是右子树。
3.3 二叉树性质
1)在二叉树的第i层上最多有2i-1 个节点 。(i>=1)
2)二叉树中如果深度为k,那么最多有2k-1个节点。(k>=1)
3)n0=n2+1 n0表示度数为0的节点数,n2表示度数为2的节点数。
4)在完全二叉树中,具有n个节点的完全二叉树的深度为[log2n]+1,其中[log2n]是向下取整。
5)若对含 n 个结点的完全二叉树从上到下且从左至右进行 1 至 n 的编号,则对完全二叉树中任意一个编号为 i 的结点有如下特性:
(1) 若 i=1,则该结点是二叉树的根,无双亲, 否则,编号为 [i/2] 的结点为其双亲结点;
(2) 若 2i>n,则该结点无左孩子, 否则,编号为 2i 的结点为其左孩子结点;
(3) 若 2i+1>n,则该结点无右孩子结点, 否则,编号为2i+1 的结点为其右孩子结点。
3.5 满二叉树
满二叉树:在一棵二叉树中。如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。
满二叉树的特点有:
1)叶子只能出现在最下一层。出现在其它层就不可能达成平衡。
2)非叶子结点的度一定是2。
3)在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多。
图3.4 满二叉树
3.6 完全二叉树
完全二叉树:对一颗具有n个结点的二叉树按层编号,如果编号为i(1<=i<=n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树。
图3.5展示一棵完全二叉树
特点:
1)叶子结点只能出现在最下层和次下层。
2)最下层的叶子结点集中在树的左部。
3)倒数第二层若存在叶子结点,一定在右部连续位置。
4)如果结点度为1,则该结点只有左孩子,即没有右子树。
5)同样结点数目的二叉树,完全二叉树深度最小。
注:满二叉树一定是完全二叉树,但反过来不一定成立。
二叉树
▪ 非线性结构
▪ 数据元素(结点)按分支关系组织起来的结构
▪ 每个结点最多有俩个子树的有序树
结点与度
度就是一个结点下面的子树,度为几就是一个结点下面有几个树,度为0的结点是叶子结点,D和E是B的度
完全二叉树的特点
▪ 叶子结点只可能在最大俩层出现
\QQ图片20210307231637.png)]
红笔的1 2 3是树的层次,只有倒数第一和倒数第二的层次才能有叶子结点
▪ 对任意一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L + 1(换言之子树必须向左对齐)
片\QQ图片20210307231833.png)]
如在3下面加一个右子树7是不行的,必须先加一个左子树,才能加上这个右子树7
▪ 度为1的结点只有0或1个
非完全二叉树和完全二叉树的区别
非完全二叉树可以单独存在右子树,完全二叉树子树一定要先左子树,再右子树,不能单独存在右子树。