【万题详解】DFS搜索专题合集(上)

专栏推荐

我的专栏------
专栏链接

1.文章平均质量分 70分以上

2.以洛谷题为基础,解决C++问题

3.有题目、讲解、思路、参考代码......

  1. 文章数:29 (2024.3.8)

课前C++小程序(脱控极域电子教室)

这个图标相信现在的学生党没有人想看到

而且每个人都想干掉这款软件,

今天,喷火龙廖 就来聊一下,如何脱控极域电子教室。

那到底该咋做捏?

正片开始

作为编程博主,不如咱先用C++写一遍,看看行不行

cpp 复制代码
#include<bits/stdc++.h>
#include<windows.h>
using namespace std;
int main(){
	Sleep(1000);
	system("TASKKILL /F /IM StudentMain.exe /T");
	return 0;
}

亲测有效,推荐指数:

缺点:紧要关头没有时间编译运行😑

卡BUG(绝对成功)

同样,召唤出粘滞键,

用鼠标摁住这个界面(不要松),同时按Win+Tab

将粘滞键界面关掉,再次按Win+Tab ,并按两下Win键,回到极域界面,会弹出极域崩溃的提示,按退出即可,

亲测有效,推荐指数:

提示

不会用洛谷的可以看看这篇文章------洛谷使用指南

还有,以下链接是题目的链接。

P1036 [NOIP2002 普及组] 选数

P1706 全排列问题

P1157 组合的输出

P1236 算24点

P1036 [NOIP2002 普及组] 选数

题目描述

已知 n 个整数 1,2,⋯ ,x1​,x2​,⋯,xn​,以及 11 个整数 k(k<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 个整数,分别为 1,2,⋯ ,x1​,x2​,⋯,xn​(1≤xi​≤5×106)。

输出一个整数,表示种类数。

输入输出样例

输入 #1

4 3

3 7 12 19

输出 #1

1

解题思路

这个题我也是卡了好久,看书的时候突然想到用深度搜索很适合解这道题。 我设置的变量是

  • i,代表第i个数
  • nums,代表已经加了几个数
  • sum,加了nums个数之后的总和
  • ans,要输出的答案,初始化为0

dfs函数如下:dfs(i,nums,sum) 思路是,在面对第i个数时,我们有两种选择,一个是加第i个数,一个是不加第i个数,加的话,我们就把i+1(处理下一个数),sums+1,sum+num[i]放到dfs里递归,不加的话,就把i+1(还是要处理下个数),nums,sum(不用动,因为没有加第i个数)放到dfs里递归。

还有限制条件,如果nums==k时,就代表已经加了k个数,此时检测sum是否是素数,如果是的话,ans++。

还有i要小于等于n。

AC

cpp 复制代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
constexpr int N=25;
int n,k,z=0,s[N],st[N],sum=0,ans=0;
bool pd(int n){
    for(int i=2;i*i<=n;i++){
        if(n%i==0){
            return false;
        }
    }
    return true;
}
void dfs(int u,int sum,int start){
    if(u==k){
        if(pd(sum))
            ans++;
        return;
    }
    for(int i=start;i<n;i++) {
        dfs(u + 1, sum + s[i], i + 1);
    }
        return;
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++){
        scanf("%d",&s[i]);
    }
    dfs(0,0,0);
    printf("%d\n",ans);
    return 0;
}

P1706 全排列问题

题目描述

按照字典序输出自然数 1 到 n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式

一个整数 n。

输出格式

由 1∼n 组成的所有不重复的数字序列,每行一个序列。

每个数字保留 55 个场宽。

输入输出样例

输入 #1

3

输出 #1

1 2 3

1 3 2

2 1 3

2 3 1

3 1 2

3 2 1

说明/提示

1≤n≤9。

解题思路

我是用搜索来做的

a数组是用来存放当前选择的排列顺序,b数组则是用来判断当前数是否在a数组中

出现过(其中1表示出现过,0表示未出现过).

本题解思路是这样的:

按1~n的顺序枚举第i位(用搜索来过渡),再逐个判断1~n中哪个数是当前序

列没有出现过的------如果出现过,则将它存储到a数组中,继续下一位的枚举;否

则就继续下一个数的枚举.当第n位枚举完1~n时,就可以直接输出a数组.完事后,

再退回上一位,如果上一位也枚举完1~n后,就再继续退回;如果未枚举完,则把

a的当前位置清空,把b[i]的数变成0(就是代表没有出现过).

最后,如果n位都枚举完1~n之后,就可以stop了...

AC

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int a[10],n;
bool vis[10];
void dfs(int u){
	if(u>n){
		for(int i=1;i<=n;i++){
			cout<<setw(5)<<a[i];
		}
		cout<<endl;
		return;
	}
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			a[u]=i;
			vis[i]=1;
			dfs(u+1);
			vis[i]=0;
		}
	}
}
int main(){
	cin>>n;
	dfs(1);
	return 0;
}

P1157 组合的输出

题目描述

排列与组合是常用的数学方法,其中组合就是从 n 个元素中抽出 r 个元素(不分顺序且 r≤n),我们可以简单地将 n 个元素理解为自然数 1,2,...,n,从中任取 r 个数。

现要求你输出所有组合。

例如 n=5,r=3,所有组合为:

123,124,125,134,135,145,234,235,245,345。

输入格式

一行两个自然数 r(1<n<21,0≤r≤n)。

输出格式

所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。

注意哦!输出时,每个数字需要 33 个场宽。

以 C++ 为例,你可以使用下列代码:

cout << setw(3) << x;

输出占 33 个场宽的数 x。注意你需要头文件 iomanip

输入输出样例

输入 #1

5 3

输出 #1

1 2 3

1 2 4

1 2 5

1 3 4

1 3 5

1 4 5

2 3 4

2 3 5

2 4 5

3 4 5

解题思路

这题其实就是搜索+回溯(可是我仍然写了半个多小时)

首先,第一组排列一定是 1∼k(前 k 个元素),于是进行一个预处理;

接下来开始搜:

先从第 k 个元素搜,搜完前 k−1 个元素为 1∼k−1 时最后一个元素的所有情况(边搜边记);

搜完了(前 k 个元素填满了或任意一个元素 >n 了或前 k 个元素未填满,但目前元素已经到 n 了(下一步就没了))就回溯(第一种情况下输出);

共搜 k 次,每次范围向前 1个元素,初始值为 x(目前在搜第几个元素)

搜完了就好了。

AC

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int r,a[100],n;
void dfs(int k){
    int i;
    if(k>r){
        for(i=1;i<=r;i++){
            cout<<setw(3)<<a[i];
        }
        cout<<endl;
        return ;
    }
    for(i=a[k-1]+1;i<=n;i++){
        a[k]=i;
        dfs(k+1);
    }
}  
int main()  
{   
    cin>>n>>r;
    dfs(1);
    return 0;  
}  

P1236 算24点

题目描述

几十年前全世界就流行一种数字游戏,至今仍有人乐此不疲.在中国我们把这种游戏称为"算 24点"。您作为游戏者将得到 4 个 1∼9 之间的自然数作为操作数,而您的任务是对这 4个操作数进行适当的算术运算,要求运算结果等于 24。

您可以使用的运算只有:+,-,*,/您还可以使用 ()来改变运算顺序。注意:所有的中间结果须是整数,所以一些除法运算是不允许的(例如,(2 ×2)/4 是合法的,2×(2/4)是不合法的)。下面我们给出一个游戏的具体例子:

若给出的 4 个操作数是:1 、 2 、 3 、 7,则一种可能的解答是 1+2+3 ×7=24。

输入格式

只有一行,四个1到9之间的自然数。

输出格式

如果有解的话,只要输出一个解。输出的是三行数据,分别表示运算的步骤。

  • 其中第一行是输入的两个数和一个运算符和运算后的结果;

  • 第二行是第一行的结果和一个输入的数据、运算符、运算后的结果,或者是另外两个数的输出结果;

  • 第三行是前面的结果第二行的结果或者剩下的一个数字、运算符和 =24=24。如果两个操作数有大小的话则先输出大的。

如果没有解则输出 No answer!

如果有多重合法解,输出任意一种即可。

注:所有运算结果均为正整数。

输入输出样例

输入 #1

1 2 3 7

输出 #1

2+1=3

7*3=21

21+3=24

解题思路

我的思路是从剩下的数中不断枚举2个数,一一尝试加减乘除四则运算。题目要求从较大数开始输出,我就要求运算时前一个量大于等于(一定要加"等于"!否则60分!)后一个量。然后将结果存在较大量中,并设较小量为已访问。跳过已访问的数,不断从第一个数搜到第四个数搞运算,顺便将运算符号和运算的两个量存起来。当只剩最后一个未访问数时,若其为24,输出即可。

易错点:

1、当4个数中出现两个及以上相同数时,注意两数相同也可以进行运算,但必须保证运算的两个量下标不同。(get60分)

输入:2 2 2 4 输出:2+2=4 4+2=6 6*4=24

2、运算中必须保证只有整除(无余数)。

3、得出的24可以在4个数中的任意一个(要把四个数全搜一遍)

4、运算中不能出现0和负数(特判解决)。

5、可能会出现两个数反复运算(即最后结果被设为已访问),此时特判最后结果未访问即可(get70分)。

6、必须保证24是最后一步算出来的(在运算出结果时判断,若为24则return,get100分)。

输入:1 2 4 6 输出:2-1=1 4*1=4 6*1=24

AC

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int a[5];
char opt[5]= {' ','+','-','*','/'};
int F(int x,int k, int y)                                 
{
  if(k==1)
    return x+y;
  if(k==2)
    return max(x,y)-min(x,y);
  if(k==3)
    return x*y;
  return (y==0 || x<y || x%y!=0) ? -999999 : x/y;
}
void Out(int a,int b,int c,int d,int e,int f,int k1,int k2,int k3)
{
  printf("%d%c%d=%d\n",max(a,b),opt[k1],min(a,b),F(max(a,b),k1,min(a,b)));
  printf("%d%c%d=%d\n",max(c,d),opt[k2],min(c,d),F(max(c,d),k2,min(c,d)));
  printf("%d%c%d=%d\n",max(e,f),opt[k3],min(e,f),F(max(e,f),k3,min(e,f)));
  exit(0);                                                  
}
int main()
{
  scanf("%d%d%d%d", &a[1],&a[2],&a[3],&a[4]);
  sort(a+1,a+5);                                           
  do
  {
    for (int i = 1; i <= 4; i++)                            
      for (int j = 1; j <= 4; j++)
        for (int k = 1; k <= 4; k++)
            if (F(F(F(a[1],i,a[2]),j,a[3]),k,a[4])==24)       //((a?b)?c)?d
                Out(a[1],a[2],F(a[1],i,a[2]),a[3],F(F(a[1],i,a[2]),j,a[3]),a[4],i,j,k);
            else if (F(F(a[1],i,a[2]),k,F(a[3],j,a[4])) == 24)//(a?b)?(c?d)
                Out(a[1],a[2],a[3],a[4],F(a[1],i,a[2]),F(a[3],j,a[4]),i,j,k);
  }while (next_permutation(a + 1, a + 5));
  puts("No answer!");
  return 0;
}

结尾

希望大家多多关注!!!

如果你能支持一下我,我十分感谢!!!

如果有人想在洛谷上做题,可以点下方链接:

https://www.luogu.com.cn/

如果你喜欢或想了解一下其他的算法,可以看看以下这些:

洛谷指南

洛谷使用指南_洛谷怎么看-CSDN博客

题目详解系列(部分):

【万题详解】P1314 [NOIP2011 提高组] 聪明的质监员-CSDN博客

【万题详解】洛谷P1282 多米诺骨牌-CSDN博客

【万题详解】洛谷P1238 走迷宫-CSDN博客

【万题详解】洛谷P1135奇怪的电梯-CSDN博客

【万题详解】洛谷P1510 精卫填海-CSDN博客

【万题详解】洛谷P1252 马拉松接力赛-CSDN博客

【万题详解】洛谷P1359 租用游艇-CSDN博客

【百题详解】洛谷P8508 做不完的作业-CSDN博客

【万题详解1】洛谷P1230 智力大冲浪-CSDN博客

【全网首发】洛谷贪心题解合集2-CSDN博客

【全网首发】洛谷贪心题解集合-CSDN博客

洛谷二分题集(3题)-CSDN博客

游戏系列:

C++棋类小游戏2-CSDN博客

C++自创棋类小游戏-CSDN博客

C++:史上最坑小游戏-CSDN博客

C++:自创小游戏-CSDN博客

C++:下雪-CSDN博客

C++讲解系列(算法):

C++:第十五讲高精度算法-CSDN博客

C++:第十四讲动态规划初步-CSDN博客

C++:第十三讲BFS广度优先搜索-CSDN博客

C++:第十二讲DFS深搜(二)_c++匿名函数dfs-CSDN博客

C++:第十一讲DFS深搜-CSDN博客

C++:第十讲二分查找-CSDN博客

前缀和与差分:

C++:第九讲前缀和与差分-CSDN博客

贪心:

C++:第八讲贪心算法1-CSDN博客

C++讲解系列(基础入门):

排序:

C++:第七讲冒泡排序-CSDN博客

函数:

C++第6讲max和min函数_c++ min函数-CSDN博客

C++第五讲函数初步-CSDN博客

for循环&数组:

C++第四讲for循环及数组-CSDN博客

if语句&else语句及运算:

C++第三讲:C++中的逻辑运算符及if else语句-CSDN博客

基础:

C++第二讲输入与输出-CSDN博客

C++第一讲认识C++编译器-CSDN博客

欢迎收看,希望大家能三连!

最后认识一下,我是爱编程的喷火龙廖,我们有缘再见!

相关推荐
此生只爱蛋18 分钟前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
何曾参静谧37 分钟前
「C/C++」C/C++ 指针篇 之 指针运算
c语言·开发语言·c++
咕咕吖1 小时前
对称二叉树(力扣101)
算法·leetcode·职场和发展
九圣残炎1 小时前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
lulu_gh_yu1 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
丫头,冲鸭!!!2 小时前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
Re.不晚2 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
ULTRA??2 小时前
C加加中的结构化绑定(解包,折叠展开)
开发语言·c++
凌云行者3 小时前
OpenGL入门005——使用Shader类管理着色器
c++·cmake·opengl
凌云行者3 小时前
OpenGL入门006——着色器在纹理混合中的应用
c++·cmake·opengl