.DFS.

DFS

全称为Depth First Search,中文称为深度优先搜索。
这是一种用于遍历或搜索树或图的算法,其思想是:
沿着每一条可能的路径一个节点一个节点地往下搜索,
直到路径的终点,然后再回溯,直到所有路径搜索完为止。

DFS俗称爆搜,最重要的就是顺序
需要思考的是,应该用什么样的顺序来搜索答案
用树的形式展开
假设已经有n个空位了,那么就从第一个开始填,
从前向后一个空位一个空位的填充,且每一次填充的数字不能与前面填充的数字一样
深搜是优先向下走,即先填充好一条路径,填好后,会向前回溯。
每次存的都是当前的路径,回溯后前面的路径就不存在了,
所以整体看来是一棵树,实际上每次只能有一条分支,且最后回溯之后就什么也没了

题目:842. 排列数字 - AcWing题库

 思路:

思路挺简单的:一层for循环,如果当前的数没有被用过,那么就使用它。
st[i]表示当前的数是否被用过
path[x]用来储存将要被使用的数

这里dfs中,dfs的路径表示的是长度,即不断向下深搜
第二个for循环表示的是宽度,即向右深搜,直到找到一个没有被用过的数字。

tips
可以自己模拟一下,但是要注意该层dfs()结束的标志可以是第一层for循环结束,也可以是第二层for循环结束,而且在回溯的过程中,只要存在满足第二层循环里的if(!st[i])语句就会开辟新的路径,向下深搜

 代码:

#include<iostream>

using namespace std;

int path[10];
bool st[10];
int n;

void dfs(int x)
{
    //说明到最后一排——即走完了该条路径
    if(x==n)
    {
        for(int i=0;i<n;i++) cout << path[i] << " ";
        cout << endl;
    }
    else 
    {
        for(int i=1;i<=n;i++)
        {
            //false表示没有被用过
            if(!st[i])
            {
                path[x]=i;//使用i
                st[i]=true;//i被使用过了
                dfs(x+1);
                //清空上一路径的数值以及操作
                path[x]=0;
                st[i]=false;
            }
        }
    }
}
int main()
{
    cin >> n;
    
    dfs(0);
    
    return 0;
}

DFS+剪枝

剪枝,顾名思义就是减去某些枝条且是没用的枝条

返回到DFS中 就是在向下深搜的过程中,如果碰到了与题目要求不符的条件,那就停止向下深搜,转为向前回溯。即可以提前判断当前操作一定是不合法的,那么就没必要继续向下搜了,直接结束,向前回溯。该操作称之为剪枝。

题目:843. n-皇后问题 - AcWing题库

 思路:

题目要求:如果该点已经有皇后了,那么该点所在的行、列,正对角线、反对角线上都不能再有第二个皇后

边深搜便判断是否与题解相斥:如果与题目要求相斥,那么就停止向下搜索,转为向前回溯

不想手动模拟的话,那么可以看一看这一篇题解:AcWing 843. n-皇后问题--图解+代码注释 - AcWing

代码:

#include<iostream>

using namespace std;

const int N=20;
//记录棋盘布局
char cow[N][N];
//l[N]表示这一列是否含有女皇,dg[N]表示该女皇的正对角线是否含有女皇,udg[N]反对角线
int l[N],dg[N],udg[N];
int n;
//深度搜索每一行
void dfs(int u)
{
    if(u==n)
    {
        for(int i=0;i<n;i++)
        {
         for(int j=0;j<n;j++)
              printf("%c",cow[i][j]);
        printf("\n");
        }
        printf("\n");
    }
    
    for(int i=0;i<n;i++)
    {
        //如果满足该女皇所在列、对角线、反对角线都没有别的女皇的话
        if(!l[i] && !dg[u+i] && !udg[n-i+u])
        {
            //则在u行i列放下一个女皇
            cow[u][i]='Q';
            //则新放下女皇所在的列、正对角线、反对角线都不能再放置其他女皇了
            l[i]=dg[u+i]=udg[n-i+u]=true;
            //搜索下一行是否能放置女皇
            dfs(u+1);
            //还原现场
            l[i]=dg[u+i]=udg[n-i+u]=false;
            cow[u][i]='.';
        }
    }
    return;
}

int main()
{
    scanf("%d",&n);
    
    //初始化
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        cow[i][j]='.';
    }
    
    dfs(0);
    return 0;
}

tips:

dfs强烈建议手动模拟一下,要注意:dfs结束的方式不只是return,还有for循环的结束也会造成dfs的结束。这层dfs结束后就会执行上一个dfs剩下的“还原现场”的语句,接着根据是否结束本层for循环来决定是否结束上一个dfs语句。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值