常用算法代码模板与题单 | B - 搜索

【递归】

算法模板

void fun(x)
{
	if (..)
	{
		return;  // 递归退出条件
	}
	fun(y);  // 数据拆分
}

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing [[96 奇怪的汉诺塔]]
AcWing [[98 分形之城]]
AcWing [[118 分形]]
AcWing [[1152 格雷码]]
AcWing 1256 扩展二叉树
AcWing 1258 小球
AcWing 1259 二叉树遍历
AcWing 1260 二叉树输出
AcWing 1261 查找二叉树
AcWing 3429 全排列
AcWing 3483 2的幂次方
AcWing 5930 分解因数
AcWing 5931 菲波那契数列
AcWing 5932 扩号匹配问题
AcWing 5933 爬楼梯
AcWing 5934 汉诺塔问题
AcWing 5937 分数求和
AcWing 5939 判断元素是否存在
AcWing 5957 黑白棋子的移动
AcWing 6049 求后序遍历
AcWing 6050 对称二叉树
洛谷 B2142 求 1+2+3+...+N 的值 入门
洛谷 B2144 阿克曼(Ackermann)函数 入门
洛谷 B2145 digit 函数 入门
洛谷 B2146 Hermite 多项式 入门
洛谷 B2147 求 f(x,n) 入门
洛谷 B2148 再求 f(x,n) 入门
洛谷 [[P2907 Roads Around The Farm]] 入门
洛谷 P5739 计算阶乘 入门
洛谷 P1010 幂次方 普及-
洛谷 P5657 格雷码 普及-
洛谷 P5461 赦免战俘 普及
洛谷 [[AT_abc466_f Many Mod Calculation]] 提高+ ⭐⭐⭐⭐⭐ 前缀最小值压缩 + 递归计数 + 二分查找 将冗余模数压缩为严格递减序列 \(b\),从右往左预处理 \(f[i]\)\([0,b[i]-1]\) 内满足 \(f(x)=0\) 的个数),查询时用二分定位当前适用的最小模数,利用周期性分层计数(完整周期贡献 \(\lfloor value/b_i \rfloor \cdot f[i]\),余数递归),时间复杂度 \(O(T \cdot (N + k^2))\),空间复杂度 \(O(k)\)

【DFS - 一维】

算法模板

void dfs(int u)
{
    if (u==n)
	{  // 到达n层后结束搜索
        for (int i=0; i<n; i++)
		{
			// 按照题目要求执行,或者打印、计算等
        }
        return ;  // 一定要加这句返回
    }
	// 注意:DFS没有通用模板,每道题都有自己的顺序,这里需要根据每道题进行修改
    for (int i=1; i<=n; i++)
	{  // 每个位置可以遍历的内容,如这里是可以填入1~n的数字
        if (!st[i])
		{  // 判断状态,确定是否可以填入
            path[u] = i;
            st[i] = true;
            dfs(u+1);  // DFS搜索
            // path[u] = 0; // 可以不要这句,因为每次都被赋值
            st[i] = false;
        }
    }
}
// 从第0层开始遍历
dfs(0);
// 剪枝方法1
// 增加sum参数,直接传递当前已选数的总和,避免重复计算,从而提高效率
void dfs(int step, int sum)

// 剪枝方法2
// 只要满足一种方案就退出
void dfs(int step)
{
    if (flag) return;
}

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 92 递归实现指数型枚举
AcWing 93 递归实现组合型枚举
AcWing 94 递归实现排列型枚举
AcWing 165 小猫爬山
AcWing 167 木棒
AcWing 168 生日蛋糕
AcWing 171 送礼物
AcWing 460 子矩阵
AcWing 842 排列数字
AcWing 1111 字母
AcWing 1115 取石子游戏
AcWing 1117 单词接龙
AcWing 1118 分成互质组
AcWing 3428 放苹果
AcWing 5940 素数环
AcWing 5941 自然数的拆分
AcWing 6099 座位
洛谷 AT_abc425_b Find Permutation 2 入门
洛谷 AT_abc356_c Keys 普及-
洛谷 AT_abc357_c Sierpinski carpet 普及-
洛谷 AT_abc358_c Popcorn 普及-
洛谷 AT_abc363_c Avoid K Palindrome 2 普及-
洛谷 AT_abc367_c Enumerate Sequence 普及-
洛谷 AT_abc371_c Make Isomophic 普及-
洛谷 AT_abc374_c Separated Lunch 普及-
洛谷 AT_abc404_d Goin' to the Zoo 普及-
洛谷 AT_abc416_c Concat (X-th) 普及-
洛谷 AT_abc427_c Bipartize 普及-
洛谷 B3621 枚举元祖 普及-
洛谷 B3623 枚举排列(递归实现排列型枚举) 普及-
洛谷 [[B3850 幸运数]] 普及-
洛谷 P1036 选数 普及-
洛谷 P1087 FBI树 普及-
洛谷 P1157 组合的输出 普及-
洛谷 [[P1218 特殊的质数肋骨]] 普及-
洛谷 [[P1460 健康的荷斯坦奶牛]] 普及-
洛谷 P1706 全排列问题 普及-
洛谷 P1827 美国血统 普及-
洛谷 P2036 PERKET 普及-
洛谷 P2392 kkksc03考前临时抱佛脚 普及-
洛谷 P2404 自然数的拆分问题 普及-
洛谷 P2677 Bookshelf 2 普及-
洛谷 [[P6183 The Rock Game]] 普及-
洛谷 [[P8185 Blocks]] 普及-
洛谷 [[P9011 Air Cownditioning II]] 普及-
洛谷 [[P10377 好斗的牛]] 普及-
洛谷 P10448 组合型枚举 普及-
洛谷 AT_abc382_d Keep Distance 普及
洛谷 B3622 枚举子集(递归实现指数型枚举) 普及
洛谷 P1019 单词接龙 普及
洛谷 [[P1118 Backward Digit Sums]] 普及
洛谷 [[P1215 母亲的牛奶]] 普及
洛谷 P1228 地毯填补问题 普及
洛谷 P1259 黑白棋子的移动 普及
洛谷 P1498 南蛮图腾 普及
洛谷 P1928 外星密码 普及
洛谷 [[P5194 Scales]] 普及
洛谷 AT_abc390_d Stone XOR 普及+
洛谷 P1034 矩形覆盖 普及+
洛谷 P1043 数字游戏 普及+
洛谷 P1310 表达式的值 普及+
洛谷 P1433 吃奶酪 普及+
洛谷 P1549 棋盘问题 普及+
洛谷 P1731 生日蛋糕 普及+
洛谷 P9126 Moo Route II 普及+
洛谷 [[P10483 小猫爬山]] 普及+
洛谷 P1092 虫食算 提高+
洛谷 P1120 小木棍 提高+
洛谷 P1312 Mayan游戏 提高+
洛谷 [[AT_abc468_c Between P and Q]]
洛谷 [[U207723 分成互质组(Coplasm group)]]
AtCoder AT_awc0003_e Cargo Delivery Truck
AtCoder AT_awc0010_e Exhibition Booth Arrangement
学而思编程 安全密码 普及奠基 ⭐⭐ DFS 枚举 + 剪枝 字典序\(3 \to 6 \to 9\))逐位 DFS 枚举 \(n\) 位密码,用全局计数器 cnt 记录已生成的合法密码数;填第 step 位时检查是否与前一位构成禁止组合(\(36\)\(69\)\(93\)),若构成则 continue 剪枝跳过;当 step > ncnt++,若 cnt == k 则输出当前密码并结束;递归深度为 \(n\),最坏时间复杂度 \(O(3^n)\),空间复杂度 \(O(n)\)
学而思编程 数字和为x的整数 语言基础 DFS / 枚举 按位数 DFS 生成所有不超过 \(n\) 的数字,筛选数位和等于 \(x\) 的,注意去重和剪枝。
学而思编程 素数加法算式 普及进阶 ⭐⭐⭐ DFS(子集枚举) 用数组 c[i] 标记第 \(i\) 个字符后是否插入加号(\(0\) 表示不分割,\(1\) 表示分割),DFS 枚举所有 \(2^{n-1}\) 种分割方案,对每种方案按分割位置将字符串拆分为若干数字并求和,用试除法 \(O(\sqrt{sum})\) 判断总和是否为素数,统计素数方案数,时间复杂度 \(O(2^{n-1} \cdot n \cdot \sqrt{sum})\)\(n \le 10\)\(sum\) 最大约 \(10^{10}\))。

【DFS - 二维】

算法模板

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 166 数独
AcWing 843 n-皇后问题
AcWing 1112 迷宫
AcWing 1113 红与黑
AcWing 1114 棋盘问题
AcWing 1116 马走日
AcWing 2770 方格取数
AcWing 3472 八皇后
AcWing 5976 细胞
AcWing 6037 连通块
AcWing 6046 围成面积
洛谷 AT_abc378_d Count Simple Paths 普及-
洛谷 P1605 迷宫 普及-
洛谷 [[P1644 跳马问题]] 普及-
洛谷 AT_abc374_d Laser Marking 普及
洛谷 AT_abc424_d 2x2 Erasing 2 普及
洛谷 P1219 八皇后 普及
洛谷 [[P1671 Rigging the Bovine Election]] 普及
洛谷 [[P10379 俄罗斯方块]] 普及
洛谷 P3956 棋盘 普及+
洛谷 P1074 靶形数独 提高+
洛谷 U543688 传教士
学而思编程 六面世界3 普及进阶 ⭐⭐ DFS/BFS(连通分量计数) 将坐标偏移 \(+1000\) 避免负坐标后存入二维数组 a,对每个黑色格子用 DFS/BFS 向六方向 \((\pm1,0),(0,\pm1),(1,1),(-1,-1)\) 扩展遍历整个连通块并标记访问,遍历所有格子时若遇到未访问的黑色格子则启动新的 DFS/BFS 并累加连通分量计数器,最终输出连通分量个数,时间复杂度 \(O(N)\)\(N \le 2000\),每个格子最多访问一次)。

【BFS - 一维】

算法模板

// 该模板存在问题是队列长度只增不减,可使用vector方式保持队列长度始终在范围内
typedef pair<int, int> PII;  // 三个及以上的参数适合用结构体
PII q[N*N];
int d[N][N];  // 记录每个点到起点的距离
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
int bfs()
{
	int hh=0, tt=0;
	q[0] = {0, 0};
	memset(d, -1, sizeof(d));  // 初始化每个点到起点的距离
	d[0][0] = 0;  // 起点的距离为0
	while (hh<=tt)
	{
		auto t = q[hh++];
		for (int i=0; i<4; i++)
		{
			int x = t.first+dx[i], y = t.second+dy[i];
			if (x>=0 && x<n && y>=0 && y<m && g[x][y]==0 && d[x][y]==-1)
			{
				d[x][y] = d[t.first][t.second]+1;
				q[++tt] = {x,y};
			}
		}
	}
	return d[n-1][m-1];
}
bfs()  // 调用bfs(),返回最短路径

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 190 字串变换
AcWing 1100 抓住那头牛
AcWing 6047 奇怪的电梯
洛谷 AT_abc424_c New Skill Acquired 普及-
洛谷 [[P1588 Catch That Cow]] 普及-
洛谷 [[P2959 The Leisurely Stroll]] 普及-
洛谷 AT_abc361_d Go Stone Puzzle 普及
洛谷 AT_abc451_d Concat Power of 2 普及
洛谷 P1135 奇怪的电梯 普及
洛谷 P3958 奶酪 普及
洛谷 P4017 最大食物链计数 普及
洛谷 P1032 字串变换 普及+
洛谷 P2730 魔板 Magic Squares 普及+
AtCoder AT_awc0031_c Island Hopping Adventure
AtCoder AT_awc0033_c Spread of Rumors
AtCoder AT_awc0035_c Chain Blackout

【BFS - 二维】

算法模板

单源BFS

// 用vector改写
typedef pair<int, int> PII;  // 三个及以上的参数适合用结构体
queue<PII> q;
int d[N][N];  // 记录每个点到起点的距离,这里无需vis数组(dist[][]==-1表示没走过)
int dx[4]={-1, 1, 0, 0};
int dy[4]={0, 0, -1, 1};
void bfs()
{
	memset(d, -1, sizeof(d));  // 初始化每个点到起点的距离
	q.push({0,0});
	d[0][0] = 0;  // 起点的距离为0
	while (!q.empty())
	{
		int x = q.front().first, y = q.front().second;
		q.pop();
		for (int i=0; i<4; i++)
		{
			int nx = x+dx[i], ny = y+dy[i];
			if (nx<1 || nx>n || ny<1 || ny>n || g[nx][ny]==1 || d[nx][ny]!=-1)
				continue;
			d[nx][ny] = d[x][y]+1;
			q.push({nx, ny});
		}
	}
}
bfs()  // 调用bfs(),dist[i][j]中保存着最短路

多源BFS

// 与单源BFS不一样的地方在与需要将多个值压入队列
void bfs()
{
	// ...
	for (int i=1; i<=cur; i++)
		q.push(a[i]);
	// ...
}

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 173 矩阵距离
AcWing 175 电路维修
AcWing 188 武士风度的牛
AcWing 844 走迷宫 简单 ⭐⭐ BFS(广度优先搜索) 队列从起点 \((1,1)\) 开始逐层扩展,每次取出队首节点后遍历上下左右四个方向(dx[4]={-1,0,1,0}dy[4]={0,1,0,-1}),若新坐标在边界内、不是障碍、未访问(d[x][y]==-1)则更新距离 d[nx][ny]=d[x][y]+1 并入队;数组模拟队列时 hh 为头指针、tt 为尾指针,d 数组同时作为距离和访问标记(初始化为 -1);BFS 第一次到达终点 \((n,m)\) 时的距离即为最短路径,时间复杂度 \(O(n \times m)\)
AcWing 845 八数码
AcWing 1076 迷宫问题
AcWing 1096 地牢大师
AcWing 1097 池塘计数
AcWing 1098 城堡问题
AcWing 1099 仙岛求药
AcWing 1101 献给阿尔吉侬的花束
AcWing 1102 移动骑士
AcWing 1106 山谷和山峰
AcWing 1107 魔板
AcWing 3205 最优配餐
AcWing 3675 逃离迷宫
AcWing 5977 最少步数
AcWing 5978 走迷宫
AcWing 5979 走出迷宫
洛谷 AT_abc383_c Humidifier 3 普及-
洛谷 P1162 填图颜色 普及-
洛谷 P1596 Lake Counting 普及-
洛谷 [[P1746 离开中山路]] 普及-
洛谷 [[P2873 Mud Puddles]] 普及-
洛谷 [[P2958 Papaya Jungle]] 普及-
洛谷 U483711 最大黑区域 普及-
洛谷 AT_abc387_d Snaky Walk 普及
洛谷 AT_abc400_d Takahashi the Wall Breaker 普及
洛谷 AT_abc405_d Escape Route 普及
洛谷 AT_abc407_d Domino Covering XOR 普及
洛谷 AT_abc420_d Toggle Maze 普及
洛谷 AT_abc425_d Ulam-Warburton Automaton 普及
洛谷 AT_abc436_d Teleport Maze 普及
洛谷 P1443 马的遍历 普及
洛谷 [[P1747 好奇怪的游戏]] 普及
洛谷 P1825 Corn Maze 普及
洛谷 P2385 Lilypad Pond 普及
洛谷 P2895 流星雨 普及
洛谷 [[P2960 Invasion of the Milkweed]] 普及
洛谷 [[P7995 Walking Home]] 普及
洛谷 P8628 穿越雷区 普及 ⭐⭐⭐ 状态扩展 BFS(三维状态) 用三维状态 dist[x][y][last] 表示到达 \((x,y)\) 且上一步经过的格子类型为 last(0 表示 +,1 表示 -)的最短距离;从起点 \(A\) 出发向四个方向初始化,若邻居是 +dist[nx][ny][0]=1 入队,若是 -dist[nx][ny][1]=1 入队;BFS 扩展时 need = 1-last 表示下一步需要的格子类型,只有当邻居是 need 对应的类型或为终点 \(B\) 时才可转移,更新 nlast 后入队;最终答案取 dist[edx][edy][0]dist[edx][edy][1] 的最小值,若均不可达输出 -1;时间复杂度 \(O(n^2)\)
洛谷 U203285 找到最大岛 普及
洛谷 AT_abc460_d Repeatedly Repainting 普及+ ⭐⭐⭐ 多源 BFS(八方向) + 奇偶性判断 先预处理移除内部黑格(八邻域全为黑的格子永远不会变白),然后将所有剩余黑格作为多源起点同时入队 BFS,计算每个位置到最近黑格的最短距离 f[i][j];操作 \(10^{100}\) 次后,最终颜色只与距离奇偶性有关——f[i][j] % 2 == 0 输出 #(黑色),否则输出 .(白色);八方向扩展覆盖上下左右和四个对角线,时间复杂度 \(O(H \times W)\)
洛谷 P1379 八数码难题 普及+
洛谷 [[P1849 Tractor]] 普及+
洛谷 P2845 Switching on the Lights 普及+
洛谷 [[P2919 Guarding the Farm]] 普及+
洛谷 [[P3456 GRZ-Ridges and Valleys]] 普及+
洛谷 [[P3663 Why Did the Cow Cross the Road III]] 普及+
洛谷 P5195 Knights of Ni 普及+ ⭐⭐⭐ 两次 BFS(多源 BFS) 第一次 BFS 从起点出发,计算 dist1(不能经过骑士位置 3);第二次多源 BFS所有骑士位置同时出发,计算 dist2(可以经过任何可通行区域);遍历所有灌木位置 4,取 dist1[r][c] + dist2[r][c] 的最小值作为答案(即起点→灌木→骑士的最短路径);两次 BFS 时间复杂度均为 \(O(W \times H)\)
洛谷 [[P10487 Nightmare II]] 普及+
洛谷 [[P4667 Switch the Lamp On电路维修]] 提高+
AtCoder AT_awc0083_d Escape from the Ice Rink ⭐⭐⭐ BFS + 滑动扩展(四方向) 每次移动选择一个方向后一直滑动到边界或柱子前一个格子才停止,用 BFS 按层遍历求最少移动次数;对于每个出队节点,遍历上下左右四个方向,用 while 循环模拟滑动过程(nx += dx[i], ny += dy[i]),直到超出边界或 mp.count({nx,ny}) 遇到柱子,记录滑动终点;若终点未访问过则更新距离并入队;map<PII,int> 存储柱子位置实现 \(O(\log N)\) 查询,时间复杂度 \(O(H \times W \times (H+W))\),若终点不可达输出 `-1$。
学而思编程 重新涂色 普及进阶 ⭐⭐⭐ BFS(最短路径) 从起点 \((1,1)\) 进行 BFS 求到终点 \((H,W)\) 的最短路径长度 dist[H][W](步数),若无法到达则输出 \(-1\);若能到达,最高分数等于总白格数 cnt 减去最短路径上必须经过的格子数(dist[H][W] + 1,包含起点和终点),即把不在最短路径上的所有白格涂黑,时间复杂度 \(O(H \cdot W)\)\(H,W \le 50\))。

【IDA*】

算法模板

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 180 排书
AcWing 181 回转游戏
洛谷 [[P10488 Booksort]] 普及+
洛谷 P2324 骑士精神 提高+
洛谷 [[UVA1343 旋转游戏]] 提高+
洛谷 P2540 斗地主 省选

【A*】

算法模板

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 178 第K短路
AcWing 179 八数码
洛谷 P5507 机关 提高+
其他 [[Remmarguts' Date]]

【折半搜索】

算法模板

DFS版折半搜索

void dfs(..., int type)  // type用于标记属于前半部分还是后半部分
{
	// 标准dfs过程
	if (...)
	{
		// 达到条件后的处理

		if (type==1) l[sum]++;  // 保存在前半部分
		else r[sum]++;  // 保存在后半部分
		return;
	}
	dfs(..., type);
	dfs(..., type);
}
unordered_map<int, int> l, r;  // 用map记录前半部分和后半部分
dfs(1, mid, 0, 1);  // 搜索前半部分
dfs(mid+1, n, 0, 2);  // 搜索后半部分

枚举版折半搜索

// 枚举前半部分
for (i : 前半部分)
{
	// 将结果存到map中
}
// 枚举后半部分
for (i : 后半部分)
{
	// 得到后半部分结果
	// 计算需要的前半部分的结果
	// 累加组合数(求和的过程)
}

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
洛谷 P4799 世界冰球锦标赛 普及+ ⭐⭐⭐⭐ 折半搜索(Meet in the Middle) + DFS + 二分查找 \(N\) 个数分成前后两半,分别用 DFS 枚举所有子集和存入 sasb(剪枝:若剩余最小值超过剩余预算则返回),对两个数组排序后,对于 sb 中每个元素 \(s\),用 upper_boundsa 中查找满足 sa[i] <= M - s 的个数并累加,最后加上 sa.size()sb.size()(单一半部分的方案)以及空集;将复杂度从 \(O(2^N)\) 降为 \(O(2^{N/2} \cdot N)\)
洛谷 [[P10484 送礼物]] 普及+
AtCoder AT_awc0002_e Assortment of Sweets
AtCoder AT_awc0048_e Team Formation ⭐⭐⭐⭐ 折半搜索 + 哈希表计数 \(N\) 个学生分成前后两半,前半部分用位运算枚举所有子集,用 mp1[cnt][sum] 哈希表记录选择 cnt 人、技能值和模 \(M\)sum 的方案数;后半部分同样枚举,对于每个子集计算 need_cnt = K - cnt(还需选择的人数)和 need_sum = (M - sum) % M(还需满足的余数),查询 mp1[need_cnt][need_sum] 累加答案;结果对 \(10^9+7\) 取模,将复杂度从 \(O(C(N,K))\) 降为 \(O(2^{N/2} \cdot N)\)

【迭代加深】

算法模板

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 170 加成序列
洛谷 [[UVA529 Addition Chains]] 提高+

【舞蹈链】

算法模板

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
洛谷 [[P1784 数独]] 普及
洛谷 [[P4929 舞蹈链(DLX)]] 省选
posted @ 2026-06-27 14:22  团爸讲算法  阅读(27)  评论(0)    收藏  举报