深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。
注:下面图中箭头为回溯方向

C模板:
int a[510]; //存储每次选出来的数据
int book[510]; //标记是否被访问
int ans = 0; //记录符合条件的次数
void DFS(int cur){
if(cur == k){ //k个数已经选完,可以进行输出等相关操作
for(int i = 0; i < cur; i++){
printf("%d ", a[i]);
}
ans++;
return ;
}
for(int i = 0; i < n; i++){ //遍历 n个数,并从中选择k个数
if(!book[i]){ //若没有被访问
book[i] = 1; //标记已被访问
a[cur] = i; //选定本数,并加入数组
DFS(cur + 1); //递归,cur+1
book[i] = 0; //释放,标记为没被访问,方便下次引用
}
}
}
C++模板:
vector<int> a; // 记录每次排列
vector<int> book; //标记是否被访问
void DFS(int cur, int k, vector<int>& nums){
if(cur == k){ //k个数已经选完,可以进行输出等相关操作
for(int i = 0; i < cur; i++){
printf("%d ", a[i]);
}
return ;
}
for(int i = 0; i < k; i++){ //遍历 n个数,并从中选择k个数
if(book[nums[i]] == 0){ //若没有被访问
a.push_back(nums[i]); //选定本输,并加入数组
book[nums[i]] = 1; //标记已被访问
DFS(cur + 1, n, nums); //递归,cur+1
book[nums[i]] = 0; //释放,标记为没被访问,方便下次引用
a.pop_back(); //弹出刚刚标记为未访问的数
}
}
}
学算法当然要刷题领悟啦,不然就是我这种一看就会(只是背了下来),一写就废的菜鸡 ^ - ^
下面就让我们一起看看这个俗称不撞南墙不回头算法都有哪些例题!!!
设有n个整数的集合{1,2,…,n},从中取出任意r个数进行排列(1<=r<n<=10),试列出所有的排列。
输入:n = 4, r = 3
输出:
1 2 3
1 2 4
1 3 2
1 3 4
1 4 2
1 4 3
2 1 3
2 1 4
2 3 1
2 3 4
2 4 1
2 4 3
3 1 2
3 1 4
3 2 1
3 2 4
3 4 1
3 4 2
4 1 2
4 1 3
4 2 1
4 2 3
4 3 1
4 3 2
24
在这里某个元素按不同次序出现的组合应视为不同的排列。例如:1 2 3和2 1 3,元素均为1.2.3,只是排列顺序不同,因此应视为元素1.2.3的不同排列。
实现过程:
特别地,当n=r时,称为n的全排列。实现时只需把下面程序的终点改为cur==n即可。
#include<iostream>
using namespace std;
int n, r, ans; //r个数进行全排列 ans为排列个数
int book[510]; //标记是否被访问
int a[510]; //记录每次的排列数据
void DFS(int cur){ //从{1,2,...,n}中取r个数构成的排列
if(cur == r){ //已经去够r个数
for(int i = 0; i < cur; i++){ //循环输出
cout << a[i] << ' ';
}
cout << endl;
ans++; //数量加1
return ;
}
for(int i = 1; i <= n; i++){ //循环遍历保证不漏
if(!book[i]){ //若没访问过
book[i] = 1; //标记已访问
a[cur] = i; //i符合条件加入
DFS(cur + 1); //寻找一个数字
book[i] = 0; //回溯:清除标记
}
}
}
int main(){
cin >> n >> r;
DFS(0);
cout << ans << endl;
return 0;
}
【LeetCode每日一题】46. 全排列 —— DFS算法(C/C++)
给定一个不含重复数字的数组 nums ,返回其所有可能的全排列 。你可以 按任意顺序 返回答案。
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
具体分析与提交答案请点击题目,这里就不在一一赘述!!!
vector<vector<int>> ans; //记录答案
vector<int> a; // 记录每次排列
map<int, int> book; //标记是否被访问
void DFS(int cur, int n, vector<int>& nums){
if(cur == n){
ans.push_back(a);
return ;
}
for(int i = 0; i < n; i++){
if(book[nums[i]] == 0){
a.push_back(nums[i]);
book[nums[i]] = 1;
DFS(cur + 1, n, nums);
book[nums[i]] = 0;
a.pop_back();
}
}
}
vector<vector<int>> permute(vector<int>& nums) {
int n = nums.size();
DFS(0, n, nums);
return ans;
}
【LeetCode每日一题】784. 字母大小写全排列 —— DFS算法(C/C++)
给定一个字符串 s ,通过将字符串 s 中的每个字母转变大小写,我们可以获得一个新的字符串。
返回 所有可能得到的字符串集合 。以 任意顺序 返回输出。
输入:s = “a1b2”
输出:[“a1b2”, “a1B2”, “A1b2”, “A1B2”]
输入: s = “3z4”
输出: [“3z4”,“3Z4”]
提示:
1 <= s.length <= 12
s 由小写英文字母、大写英文字母和数字组成
具体思路方案与题目一差不多,这里我说一些需要用到的别的东西 ^ -^
在本题中首先使用 isdigit() 函数判断,若为数字则直接进行递归,即不用管;若为字母则使用 tolower() 函数——变为小写,然后递归,再使用 toupper() 函数——变为大写,递归。
若不明白 isdigit() 函数请看这篇:isdigit函数详解
vector<string> ans; //记录最终结果
void DFS(int cur, string s){
if(cur == s.size()){
ans.push_back(s);
return ;
}
if(isdigit(s[cur])){
DFS(cur + 1, s);
}else{
s[cur] = tolower(s[cur]);
DFS(cur + 1, s);
s[cur] = toupper(s[cur]);
DFS(cur + 1, s);
}
}
vector<string> letterCasePermutation(string s) {
DFS(0, s);
return ans;
}
【LeetCode每日一题】77. 组合 —— DFS算法(C/C++)
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
提示:
1 <= n <= 20
1 <= k <= n
具体思路与排序差不多,具体需要注意的是,这里某种数字组合的多种排列视为相同情况,因此需 “去重” 。
一种可行的方案是填数的时候:
vector<vector<int>> a; //存储排列数据
vector<int> b; // 存储每次的排列数据
void DFS(int cur, int n, int k){
if(cur == k){
a.push_back(b);
return ;
}
for(int i = 1; i <= n; i++){
int temp;
if(cur > 0) temp = b.back(); //返回b数组的最后一个元素
if((cur == 0) || (cur > 0 && i > temp)){ //第一个数或者后面的数大于前面的数
b.push_back(i); //符合加入
DFS(cur + 1, n, k); //递归选择下一个数
b.pop_back(); //弹出
}
}
}
vector<vector<int>> combine(int n, int k) {
DFS(0, n, k);
return a;
}
洛谷——P1219 [USACO1.5]八皇后 Checker Challenge
一个如下的 6 * 6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列 2 4 6 1 3 5 来描述,第 i 个数字表示在第 i 行的相应位置有一个棋子,如下:
行号 1 2 3 4 5 6
列号 2 4 6 1 3 5
这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 33 个解。最后一行是解的总个数。
输入格式:
一行一个正整数 n,表示棋盘是 n×n 大小的。
输出格式:
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
输入:6
输出:
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
问题的关键在于如何判定某个皇后所在的行、列、斜线上是否有别的皇后;可以从矩阵的特点上找到规律,如果在同一行,则行号相同;如果在同一列上,则列号相同;如果同在/斜线上的行列值之和相同;如果同在\斜线上的行列值之差相同;从下图可验证:
在摆放皇后时,可以”按行摆放”(这样就保证了皇后不会横向攻击)。即:
(1)起点为 dfs(0),即从第0行开始摆放皇后,逐行进行。同时使用一维数组 map 保存第 cur 行的皇后摆放的列,也就是说每次尝试摆放皇后的位置坐标为 (cur, map[cur]);
(2)逐列遍历,若发现位置 (i, map[j]) 与位置 (cur, map[cur]) 在同一列 或 同一主对角线 或 同一副对角线上时,摆放失败,该方案”作废”,继续执行;
(3)若摆放成功,则 dfs(cur+1),表示继续摆放下一行,过程同上;
(4)当 cur=n,即n行皇后均摆放完成时,表示该方案可行,总方案数+1。
#include<iostream>
using namespace std;
const int M = 20;
int ans = 0, n;
int a[M]; //标记i行 纵坐标为a[i]
void dfs(int cur){
int flag = 1; //标记该序列是否可行
if(cur == n){
if(ans < 3){
for(int i = 0; i < n-1; i++){
cout << a[i] << " ";
}
cout << a[n-1] << endl;
}
ans++;
return;
}
for(int i = 1; i <= n; i++){
flag = 1;
a[cur] = i;
for(int j = 0; j < cur; j++){
if(a[cur] == a[j] || cur+a[cur] == j+a[j] || cur-a[cur] == j-a[j]){
flag = 0;
break;
}
}
if(flag == 1){
dfs(cur+1);
}
}
}
int main(){
cin >> n;
dfs(0);
cout << ans << endl;
return 0;
}
素数问题有好多经典题型,例如素数环、素数和、和为素数等等;下面就来介绍几个经典例题,大家一起来学习吧。
洛谷——P1036 [NOIP2002 普及组] 选数
已知 n 个整数 x1,x2,……,xn,以及 1 个整数 k(k<nk<n)。从 n 个整数中任选 k 个整数相加,可分别得到一系列的和。例如当 n=4,k=3,4 个整数分别为 3,7,12,19 时,可得全部的组合与它们的和为:
3+7+12=22
3+7+19=29
7+12+19=38
3+12+19=34
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数:3+7+19=29。
输入格式:
第一行两个空格隔开的整数 n,k(1≤n≤20,k<n)。
第二行 n 个整数,分别为 x1,x2,……,xn(1 ≤ xi ≤ 5*10^6)
输出格式:
输出一个整数,表示种类数。
输入:
4 3
3 7 12 19
输出:
1
本题是 dfs 中的一个非常经典的问题——素数问题中的一个分支,总体思路同上,都是循环遍历加判断 cur == k ;与上面不同的地方在于本类问题需要判断素数,下面我介绍一个判断素数的方法:
#include<iostream>
using namespace std;
int a[30], book[30];
int n, k, cnt = 0;
bool Judge(int x){
for(int i = 2; i*i <= x; i++){
if(x % i == 0) return false;
}
return true;
}
void dfs(int cur, int sum, int t){
if(cur == k){
if(Judge(sum)) cnt++;
return;
}
for(int i = t; i < n; i++){
dfs(cur+1, sum+a[i], i+1);
}
return;
}
int main(){
fill(book, book + 30, 0);
cin >> n >> k;
for(int i = 0; i < n; i++){
cin >> a[i];
}
dfs(0, 0, 0);
cout << cnt << endl;
return 0;
}
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll
我正在使用Mandrill的RubyAPIGem并使用以下简单的测试模板:testastic按照Heroku指南中的示例,我有以下Ruby代码:require'mandrill'm=Mandrill::API.newrendered=m.templates.render'test-template',[{:header=>'someheadertext',:main_section=>'Themaincontentblock',:footer=>'asdf'}]mail(:to=>"JaysonLane",:subject=>"TestEmail")do|format|format.h
深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal
所以这可能有点令人困惑,但请耐心等待。简而言之,我想遍历具有特定键值的所有属性,然后如果值不为空,则将它们插入到模板中。这是我的代码:属性:#===DefaultfileConfigurations#default['elasticsearch']['default']['ES_USER']=''default['elasticsearch']['default']['ES_GROUP']=''default['elasticsearch']['default']['ES_HEAP_SIZE']=''default['elasticsearch']['default']['MAX_OP
寻找有用的ruby的好网站是什么? 最佳答案 AgileWebDevelopment列出插件(虽然不是rubygems,我不确定为什么),并允许人们对它们进行评级。RubyToolbox按类别列出gem并比较它们的受欢迎程度。Rubygems有一个搜索框。StackOverflow对最有用的rails插件和rubygems有疑问。 关于ruby-如何搜索有用的ruby,我们在StackOverflow上找到一个类似的问题: https://stacko
我有很多这样的文档:foo_1foo_2foo_3bar_1foo_4...我想通过获取foo_[X]的所有实例并将它们中的每一个替换为foo_[X+1]来转换它们。在这个例子中:foo_2foo_3foo_4bar_1foo_5...我可以用gsub和一个block来做到这一点吗?如果不是,最干净的方法是什么?我真的在寻找一个优雅的解决方案,因为我总是可以暴力破解它,但我觉得有一些正则表达式技巧值得学习。 最佳答案 我(完全)不懂Ruby,但类似这样的东西应该可以工作:"foo_1foo_2".gsub(/(foo_)(\d+)/
我读了"BingSearchAPI-QuickStart"但我不知道如何在Ruby中发出这个http请求(Weary)如何在Ruby中翻译“Stream_context_create()”?这是什么意思?"BingSearchAPI-QuickStart"我想使用RubySDK,但我发现那些已被弃用前(Rbing)https://github.com/mikedemers/rbing您知道Bing搜索API的最新包装器(仅限Web的结果)吗? 最佳答案 好吧,经过一个小时的挫折,我想出了一个办法来做到这一点。这段代码很糟糕,因为它是
给定一个元素和一个数组,Ruby#index方法返回元素在数组中的位置。我使用二进制搜索实现了我自己的索引方法,期望我的方法会优于内置方法。令我惊讶的是,内置的在实验中的运行速度大约是我的三倍。有Rubyist知道原因吗? 最佳答案 内置#indexisnotabinarysearch,这只是一个简单的迭代搜索。但是,它是用C而不是Ruby实现的,因此自然可以快几个数量级。 关于Ruby#index方法VS二进制搜索,我们在StackOverflow上找到一个类似的问题:
一般来说,我是Middleman和ruby的新手。我已经安装了Ruby我已经安装了Middleman和gem以使其运行。我需要使用slim而不是默认的模板系统。所以我安装了Slimgem。Slim的网站只说我需要'slim'才能让它工作。中间人网站说我只需要在config.rb文件中添加模板引擎,但是没有给出例子...对于没有ruby背景的人来说,这没有帮助。我在git上找了几个config.rb,它们都有:require'slim'和#Setslim-langoutputstyleSlim::Engine.set_default_options:pretty=>true#Se