【搜索】DFS搜索顺序

news/2024/10/22 18:30:41/

算法提高课笔记

目录

  • 马走日
    • 题意
    • 思路
    • 代码
  • 单词接龙
    • 题意
    • 思路
    • 代码
  • 分成互质组
    • 题意
    • 思路
    • 代码

马走日

原题链接

马在中国象棋以日字形规则移动。

请编写一段程序,给定 n∗m 大小的棋盘,以及马的初始位置 (x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点。

输入格式

第一行为整数 T,表示测试数据组数。

每一组测试数据包含一行,为四个整数,分别为棋盘的大小以及初始位置坐标 n,m,x,y。

输出格式

每组测试数据包含一行,为一个整数,表示马能遍历棋盘的途径总数,若无法遍历棋盘上的所有点则输出 0。

数据范围

1 ≤ T ≤ 9,
1 ≤ m , n ≤9,
1 ≤ n × m ≤ 28,
0 ≤ x ≤ n − 1,
0 ≤ y ≤ m − 1

输入样例

1
5 4 0 0

输出样例

32

题意

给出矩阵大小,给出马的初始位置,马只能走日。问有多少种方案让马可以遍历完棋盘上的所有点,每种方案里不可以重复经过两个点

思路

这就是典型的外部搜索,是不同状态之间的搜索,因此每次需要恢复现场(可以理解为悔棋)

代码

#include <bits/stdc++.h>using namespace std;const int N = 10;int n, m;
bool st[N][N]; // 判重
int ans;int dx[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
int dy[8] = {1, 2, 2, 1, -1, -2, -2, -1};void dfs(int x, int y, int cnt) // 前两个参数表示当前点坐标,第三个参数表示目前已经搜了多少个点
{if (cnt == n * m){ans ++ ;return;}st[x][y] = true;for (int i = 0; i < 8; i ++ ) // 遍历八个操作{int a = x + dx[i], b = y + dy[i];if (a < 0 || a >= n || b < 0 || b >= m) continue; // 位置不合法if (st[a][b]) continue; // 已遍历dfs(a, b, cnt + 1);}st[x][y] = false;
}int main()
{ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);int t;cin >> t;while (t -- ){int x, y;cin >> n >> m >> x >> y;memset(st, 0, sizeof st);ans = 0;dfs(x, y, 1);cout << ans << '\n';}
}

单词接龙

原题链接

单词接龙是一个与我们经常玩的成语接龙相类似的游戏。

现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”,每个单词最多被使用两次。

在两个单词相连时,其重合部分合为一部分,例如 beast 和 astonish ,如果接成一条龙则变为 beastonish。

我们可以任意选择重合部分的长度,但其长度必须大于等于1,且严格小于两个串的长度,例如 at 和 atide 间不能相连。

输入格式

输入的第一行为一个单独的整数 n 表示单词数,以下 n 行每行有一个单词(只含有大写或小写字母,长度不超过20),输入的最后一行为一个单个字符,表示“龙”开头的字母。

你可以假定以此字母开头的“龙”一定存在。

输出格式

只需输出以此字母开头的最长的“龙”的长度。

数据范围

n ≤ 20,
单词随机生成。

输入样例

5
at
touch
cheat
choose
tact
a

输出样例

23

提示

连成的“龙”为 atoucheatactactouchoose。

题意

给出多个字符串,首位有相同字串的两个字符串可以连接,给出开头字符,问能连接的最大长度

思路

外部搜索,每次需恢复原状

从开头字符与给定字符相同的单词开始,每次遇到能接到字符串后面的就往深遍历,(形成一个搜索树一样的结构)

下方代码有详细注释

代码

#include <bits/stdc++.h>using namespace std;const int N = 21;int n;
string word[N]; // 记录每个单词
int g[N][N]; // 记录每两个单词有多少重合
int used[N]; // 记录这个单词被用了多少次
int ans;void dfs(string dragon, int last) // 第一个参数是当前字符串 第二个参数是当前最后一个字符串编号
{ans = max((int)dragon.size(), ans); // 更新最大长度used[last] ++ ; // 更新字符串使用次数for (int i = 0; i < n; i ++ ) // 遍历每个字符串if (g[last][i] && used[i] < 2) // 条件:和当前最后一个字符串有重合 && 使用次数不到2次dfs(dragon + word[i].substr(g[last][i]), i);used[last] -- ; // 恢复
}int main()
{ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);cin >> n;for (int i = 0; i < n; i ++ ) cin >> word[i];char start;cin >> start;// 计算每两个字符串最短的重合字符个数for (int i = 0; i < n; i ++ )for (int j = 0; j < n; j ++ ){string a = word[i], b = word[j];for (int k = 1; k < min(a.size(), b.size()); k ++ ) // 从1开始,最长不超过较短字符串长度if (a.substr(a.size() - k, k) == b.substr(0, k)) // 一旦重合立刻跳出{g[i][j] = k;break;}}for (int i = 0; i < n; i ++ )if (word[i][0] == start)dfs(word[i], i);cout << ans << '\n';
}

分成互质组

原题链接

给定 n 个正整数,将它们分组,使得每组中任意两个数互质。

至少要分成多少个组?

输入格式

第一行是一个正整数 n。

第二行是 n 个不大于10000的正整数。

输出格式

一个正整数,即最少需要的组数。

数据范围

1 ≤ n ≤ 10

输入样例

6
14 20 33 117 143 175

输出样例

3

题意

每个组的数要互质,给出一系列数,问最少多少组

思路

按照组合的方式搜索,每个组里按照下表从小到大添加所有能加进去的元素,直到不能再加任何一个元素,就新开一个组

当某个数可以加到最后一组时,就没有必要新开一个组

下方代码中有详细注释

代码

#include <bits/stdc++.h>using namespace std;const int N = 10;int n;
int p[N]; // 存所有元素
int group[N][N]; // 存每个组以及其中元素
bool st[N]; // 判重
int ans = N;int gcd(int a, int b) // 找最大公约数
{return b ? gcd(b, a % b) : a;
}bool check(int group[], int gc, int i)
{for (int j = 0; j < gc; j ++ ) // 遍历group中的每个元素if (gcd(p[group[j]], p[i]) > 1) // 最大公约数大于1说明不是互质return false;return true;
}void dfs(int u, int gc, int tc, int start) // u:第几组 gc:当前组内下标 tc:当前一共有多少元素 start:当前这一组从哪个元素开始搜
{if (u >= ans) return; // 剪枝优化:如果当前组数已经大于等于ans 说明一定不是最优解 直接返回if (tc == n) ans = u; // 所有数都搜索完了bool flag = true; // true表示当前组不能继续添加新元素for (int i = start; i < n; i ++ ) // 从start开始遍历if (!st[i] && check(group[u], gc, i)) // 该元素没用过且与当前组所有元素互质{st[i] = true; // 标记该元素group[u][gc] = i; // 将该元素加入组中dfs(u, gc + 1, tc + 1, i + 1); // 下一层遍历st[i] = false; // 恢复现场flag = false; // 表示还能添加新元素}if (flag) dfs(u + 1, 0, tc, 0); // 不能添加新元素时新开一个组
}int main()
{ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);cin >> n;for (int i = 0; i < n; i ++ ) cin >> p[i];dfs(1, 0, 0, 0);cout << ans << '\n';
}

http://www.ppmy.cn/news/1000574.html

相关文章

Python的字典使用

今天做力扣上1207. 独一无二的出现次数添加链接描述时用到了python字典&#xff0c;于是把字典的用法整理了一下。 新建字典 iters {}检查字典中是否含有某一个键 iters.has_key(key)字典根据键访问值 iters[key]遍历字典的键和值 for key,value in iters.items():整体代码 c…

Ubuntu20.04之VNC的安装与使用

本教程适用于Ubuntu20.04及以下版本&#xff0c;Ubuntu22.04版本或有出入 更多更新的文章详见我的个人博客&#xff1a;【前往】 文章目录 1.安装图形桌面1.1选择安装gnome桌面1.2选择安装xface桌面 2.安装VNC-Server3.配置VCN-Server4.连接VNC5.设置VNC-Server为系统服务&…

【数据结构】二叉树、二叉搜索树、平衡二叉树、红黑树、B树、B+树

概述 二叉树&#xff08;Binary Tree&#xff09;&#xff1a;每个节点最多有两个子节点&#xff08;左子节点和右子节点&#xff09;&#xff0c;没有限制节点的顺序。特点是简单直观&#xff0c;易于实现&#xff0c;但查找效率较低。 二叉搜索树&#xff08;Binary Search…

nmake编译Qt第三方库出现无法打开包含文件type_traits

最近需要为个人项目ShaderLab添加内嵌的代码编辑窗口功能&#xff0c;支持语法高亮和Intellisense&#xff0c;最初使用了QCodeEditor,发现这个第三方的库对词法分析的实现效果不太行. 代码换行后直接缩进到首行&#xff0c;无法定位到前一句的首行 考虑换QScintilla&#xff…

容器化的好处

容器化&#xff0c;是指使用容器技术&#xff08;Docker/containerd等&#xff09;运行应用程序&#xff08;容器&#xff09;&#xff0c;并使用容器编排技术&#xff08;例如 K8s&#xff09;来管理这些容器。 我在之前的文章 《使用 Dockerfile 构建生产环境镜像》 提及普通…

Flink DataStream API详解

DataStream API 参考&#xff1a;https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/datastream_api.html Data Sources Source是程序读取其输入的位置&#xff0c;您可以使用env.addSource&#xff08;sourceFunction&#xff09;将Source附加到程序中。Fl…

随机森林算法深入浅出

随机森林&#xff08;Random Forest&#xff09;是一种集成学习&#xff08;Ensemble Learning&#xff09;算法&#xff0c;由于其优秀的表现在数据挖掘、机器学习等领域得到广泛应用。随机森林通过同时使用多个决策树对数据集进行训练&#xff0c;并通过投票机制或平均化方式…

Docker 容器转为镜像

# 容器转成镜像并指定镜像名称与版本号 # commit 时原有容器挂载的目录是不会被写入到新的镜像中去的&#xff0c;数据卷相关的都不会生效 # 但是 root 目录下新建的内容会写入到新的镜像中去 $ docker commit 容器ID 新镜像名称:版本号 $ docker commit -m"描述信息"…