14天冲刺蓝桥杯省一day4
暴力枚举
例题:数的分解(c++2019省b) 题目描述:(填空题)把 2019 分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包含数字 2 和 4,一共有多少种不同的分解方法?注意交换 3 个整数的顺序被视为同一种方法,例如 1000 + 1001 + 18 和 1001 + 1000 + 18 被视为同一种。这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。 分解成三个各不相同正整数之和*
正整数不包含2和4.(为什么要宝宝含4?正整数会有4?)这是随机分解,并不是按位分解,有多少种不同分解方法? 注意只要分解出的数字是一样的,顺序不一样也视作同一种。现在的关键词:1三数(不同)之和为2019.2顺序不影响,3数字不允许出现2,4
解题思路:这道题能不能使用暴力呢?由于是一道填空题,直接四个for循环遍历数组。对于要求3可以写一个check函数来满足要求和前面那道题一样,使用%10/10法来得到数位 bool check(int x){
while(x>0){
x%=10;
if(x2||x4) return false
n/=10;
}
return true;
} 由于总数确定,所以只用遍历三个数字。由于要去除重复的顺序,可以使用int i=1;int j=i+1;int k=j+1;的初始化方式,强行保证i<j<k,这样越往后遍历的数字越少。这可以认为是组合和排列的区别
int count=0;
for(int i=1;i<2019;i++)
{
for(int j=i+1;j<2019;j++){
for(int k=j+1;k<2019;k++){
if(check(i)&&check(j)&&check(k))
count ++;
}
例题:利用规律减少枚举次数 正整数n数量 题目描述
给你一个正整数 N,请找出所有满足如下条件的三个整数 (A, B, C) 的数量:
A ≤ B ≤ C
ABC ≤ N
保证答案不超过 2⁶³。
输入格式
一行一个整数 N。
输出格式
输出一个整数,表示答案。
样例
输入数据 1
4
输出数据 1
5
解释#1
满足条件的三元组是:(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 1, 4), (1, 2, 2)。 这背后有一套非常清晰的“剪枝”方法论,核心思想是预判,在进入循环之前,想一下进去了有没有可能产生无效结果,如果有就直接跳过这一部分。剪枝通用方法论:第一步利用数学公式反推上限,a三方大于n。如果要缩小a的循环次数,那就要找到a的什么量级过后会超过n这样不就行了。b也是一样的 第二步,利用单调性去重a<b<c就是单调性去重了,组合的思想。 第三步:将循环转换为公式计算,由于abc<n则c<n/(ab)所以c的数量为上限-下限+1.故c=n/(ab)-b+1. 最内层c的数量就是三个整数abc的数量。 在计数c的数量时要保证上限是真的大于下限的,
递归
什么是递归?递归就像查词典,词典用另外一个词来解释这个词,如果这些词里面又有不认识的词,又会去查新的词直到查到一个你所有都认识的词的地方,你就可以往回去理解每一个词了。
例题好的,这是图片中的文字内容:
【问题描述】
A + B/C + DEF/GHI = 10
这个算式中 A~I 代表 1~9 的数字,不同的字母代表不同的数字。
比如:6 + 8/3 + 952/714 就是一种解法,5 + 3/1 + 972/486 是另一种解法。
这个算式一共有多少种解法?
【答案提交】
注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。
dfs
全局状态变量
void dfs(当前状态)
{
if(当前状态是目标状态) // 判断
进行相应处理(输出当前解,更新最优解,退出返回等)
// 扩展
for(所有可行的新状态)
{
if(新状态没有访问过 && 需要访问) // 可行性剪枝、最优性剪枝、重复性剪枝
{
标记
dfs(新状态);
取消标记
}
}
}
int main()
{
...
dfs(初始状态);
...
} 全局状态变量:记录已经查询到的信息,记录最终的答案,当前的路径。 回溯三部曲:1mark:进入一个新的洞穴,先标记好,防止绕路回来,visited=true2递归,拿着绳子进入新的洞穴
3撤销,当走到死胡同的时候,必须返回上一个岔路,然后把刚才的visited=false
执行流程:1 开始在起点(初始状态) 2 判断 你看了看地图,还没到终点(不是目标状态) 3 尝试 面前有三条路(上下右)你选择了上,在起点做一个上的标记 然后调用递归dfs(上)走到上面画的格子。4 深入 在新的格子重复判断加移动的步骤。5 回溯 假设走进死胡同(既不是目标状态也无路可走),只能返回上一个格子,然后取消在起点留下的上的记号,然后尝试下这个方向。总而言之:判断-标记-移动-死胡同回退-删除标记-换方向(换方向又会回到第一个判断的操作)。
模板对应:全局变量(地图,数量) ,if(判断当前状态),for(枚举所有情况,上下左右都走一遍),if(剪枝),标记,dfs,恢复现场
例题你有一张某海域 N times N 像素的照片,. 表示海洋、# 表示陆地,如下所示:
.......
.##....
.##....
....##.
..####.
...###.
.......
其中 "上下左右" 四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有 2 座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
.......
.......
.......
.......
....#..
.......
.......
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。图片中的文字内容如下:
输入格式
第一行包含一个整数 N。(1 ≤ N ≤ 1000)。
以下 N 行 N 列代表一张海域照片。
照片保证第 1 行、第 1 列、第 N 行、第 N 列的像素都是海洋。
输出格式
一个整数表示答案。
样例 #1
样例输入 #1
7
.......
.##....
.##....
...##..
..####.
...###.
.......
样例输出 #1 为啥有两座岛屿?题目的意思是中间没有海洋那就是一片陆地。陆地旁边有海那就会被淹没(旁边全是陆地才不会被淹没),输入n代表图片n行n列,n小于1000,像素要保证四周都是海。 关键点:n最大值1000(四周要都是海),旁边有海就被淹没,计算有多少岛屿被淹(旁边全是陆地才不会被淹没) 思路:计算总岛屿的数量-上下左右都有N地链接的数量。 那如何计算总岛屿数量呢?
1全局变量定义:const int N=1010;char map[N][N];int n,tot,ok,tag;//tot岛屿数量,ok四周都有小岛的数量,tag标记(一旦发现岛屿有ok,就不再遍历其他小岛) 方向数组int dx【4】{0,0,-1,1};int dy[4]={1,-1,0,0};
2 dfs函数核心 step1:判断与移动找四周都不是海的内部点 step2标记与递归枚举与剪枝(只递归陆地部分)。当然这道题目并不需要进行恢复现场。
bfs(广度优先搜索)
bfs基本流程代码: bfs是什么?如果说dfs是一条路走到黑,那么bfs就是一圈一圈往外扩散的波纹,假设你在操场上丢了100块钱,那么dfs会选择一个方向一条路走到黑,而bfs会优先找脚下有没有然后往外半径一米的范围内有没有,这样逐渐往外扩大范围。要实现这样的一圈一圈扩大的效果,需要使用队列实现。
bfs基本流程代码全局状态变量
void BFS()
{
定义状态队列
初始状态入队
while(队列不为空)
{
取出队首状态作为当前状态
if(当前状态是目标状态)
进行相应处理(输出当前解,更新最优解,退出返回等)
else
for(所有可行的新状态)
{
if(新状态没有访问过 && 需要访问)
{
新状态入队
}
}
}
} 1全局变量:通常放的是地图,标记访问过的数组visited,方向数组。2核心函数bfs 定义状态队列:就是定义一个普通队列。 初始状态入队:将开始的位置入队如(0,0),这就是水波纹的中心。3 核心循环(只要队列不空,就一直找)然后取出第一个坐标
4判断 5扩展(核心) 如果这里不是终点,如果不是就把之前没有走过的格子丢进队列。
核心三步走:排队(把队首先丢进去)--取出(看看是不是目标)--扩散(把周围的格子放进队列)。这里2可以看出bfs的一个特点:找东西是可以最短路径的。
例题:岛屿个数(2023b)小蓝得到了一副大小为 M times N 的格子地图,可以将其视作一个只包含字符 0(代表海水)和 1(代表陆地)的二维数组,地图之外可以视作全部是海水,每个岛屿由在上/下/左/右四个方向上相邻的 1 相连接而形成。
在岛屿 A 所占据的格子中,如果可以从中选出 k 个不同的格子,使得他们的坐标能够组成一个这样的排列:(x_0, y_0), (x_1, y_1), ..., (x_{k-1}, y_{k-1}),其中 (x_{i+1%k}, y_{i+1%k}) 是由 (x_i, y_i) 通过上/下/左/右移动一次得来的(0 le i le k-1),此时这 k 个格子就构成了一个“环”。
如果另一个岛屿 B 所占据的格子全部位于这个“环”内部,此时我们将岛屿 B 视作是岛屿 A 的子岛屿。
若 B 是 A 的子岛屿,C 又是 B 的子岛屿,那 C 也是 A 的子岛屿。
请问这个地图上共有多少个岛屿?
在进行统计时不需要统计子岛屿的数目。
输入格式
第一行一个整数 T,表示有 T 组测试数据。
接下来输入 T 组数据。
对于每组数据,第一行包含两个用空格分隔的整数 M、N 表示地图大小;接下来输入 M 行,每行包含 N 个字符,字符只可能是 0 或 1。
输出格式
对于每组数据,输出一行,包含一个整数表示答案。 地图大小m*b。
浙公网安备 33010602011771号