0x22.搜索 - 深度优先搜索

这篇博客主要介绍了深度优先搜索(DFS)算法,包括其在子集和问题、全排列问题、N皇后问题中的应用。同时,博主分享了在解决这些问题时的递归回溯方法,并给出了洛谷P1219和P1562 N皇后问题的解题思路。此外,还提及了使用DFS解决AcWing 165. 小猫爬山和AcWing 166. 数独问题的方法,强调了剪枝和位运算优化的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声明:
本系列博客是《算法竞赛进阶指南》+《算法竞赛入门经典》+《挑战程序设计竞赛》的学习笔记,主要是因为我三本都买了 按照《算法竞赛进阶指南》的目录顺序学习,包含书中的少部分重要知识点、例题解题报告及我个人的学习心得和对该算法的补充拓展,仅用于学习交流和复习,无任何商业用途。博客中部分内容来源于书本和网络(我尽量减少书中引用),由我个人整理总结(习题和代码可全都是我自己敲哒)部分内容由我个人编写而成,如果想要有更好的学习体验或者希望学习到更全面的知识,请于京东搜索购买正版图书:《算法竞赛进阶指南》——作者李煜东,强烈安利,好书不火系列,谢谢配合。


下方链接为学习笔记目录链接(中转站)

学习笔记目录链接


ACM-ICPC在线模板


深度优先搜索算法是一种用于遍历或搜索树或图的算法

建立一颗搜索树,沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。

一、DFS三个经典NPC问题

三个经典深搜入门级问题。
子集和问题,全排列问题,N皇后问题。

1.子集和问题

子集和问题的一个实例为<S,c>。其中S={x1,x2,…,xn}是一个正整数的集合,c是一个正整数。子集和问题判定是否存在S的一个子集S1,使得S1中所有元素的和为c。

跟0x03递归那一节的差不多回溯递归

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<vector>
#include<unordered_map>
#define ls (p<<1)
#define rs (p<<1|1)
//#pragma GCC optimize (2)
//#pragma G++ optimize (2)//手动开 O2
#define over(i,s,t) for(register int i = s;i <= t;++i)
#define lver(i,t,s) for(register int i = t;i >= s;--i)
//#define int __int128
using namespace std;
#undef mid
typedef long long ll;
typedef pair<int,int> PII;
const int N = 30007;
const ll mod = 1e9+7;
const ll INF = 1e15+7;
const double EPS = 1e-10;
const int base = 131;//13331
int n,m,sum;
int a[N];
bool vis[N],flag;
void calc(int x){
   
   
    if(flag||vis[x]||x>n+1)return ;
    if(sum == m){
   
   
        flag = 1;
        over(i,1,n){
   
   
            if(vis[i])printf("%d ",a[i]);
        }
        return;
    }
    calc(x+1);//不选
    sum += a[x];
    vis[x] = 1;
    calc(x+1);//选
    vis[x] = 0;//回溯
    sum -= a[x];
}
int main()
{
   
   
    scanf("%d%d",&n,&m);
    over(i,1,n)
    scanf("%d",&a[i]);
    calc(1);
    if(!flag)puts("NO");
    return 0;
}

2.全排列问题

给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列。

这个懒得敲了,直接复制一个网上的代码好了

#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
using namespace std;

char allprem[1000][7];
int count = 0;

void swap(char* str,int a,int b)
{
   
   
    char tmp = str[b];
    str[b] = str[a];
    str[a] = tmp;
}
void perm(char* str,int start,int end)
{
   
   
    if(start == end - 1)
    {
   
   
        strcpy(allprem[count],str);
        count++;
    }
    else
    {
   
   
        for(int k = start;k < end;k++)
        {
   
   
            swap(str,k,start);
            perm(str,start+1,end);
            swap(str,k,start);
        }
    }
}

int compare(const void * a,const void* b)
{
   
   
    return
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁凡さん

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值