您的位置:首页 > 其它

DFS入门

2018-01-17 20:53 295 查看
Dfs       这是深度优先搜索的简称。意思是沿着HTML文件上的超链走到不能再深入为止,然后返回到某一个HTML文件,再继续选择该HTML文件中的其他超链。当不再有其他超链可选择时,说明搜索已经结束。
有点抽象,那我们来看实例吧!
Number 1:8皇后问题
题目描述
在一个n×n的棋盘上放置n个皇后,要求所有的皇后之间都不形成攻击,皇后的攻击方法与国际象棋的方法类似(朝正西北,正北,正东北,正东,正东南,正南,正西南,正西攻击)请你给出所有可能的排布方案数。
输入格式     一个整数n
输出格式     一个整数表示方案数
样例数据
input
4
output
2
数据规模与约定
n<=8
时间限制:1s
空间限制:256MB
 
这是一道很经典的dfs题,也非常老了。
从题中可以看出这题数据量非常小,那咱们就可以暴力搜索,AC这道题。
皇后可以往八个方向攻击,也就是说四条线。我们只要控制这四条线,就可以放置皇后了。横向纵向的两条线很好控制,只需要标记a[x][y]就行了,可是两条斜线怎么控制呢?
我们可以发现,对角线行列号的差或和是不变的,所以标记数组的下标为行列号的差或和即可,对于左下和右上的对角线用数组下标行列号求和标记,同时,为了避免负下标所以统一加n即可。
最大问题解决了,开始开车喽!
将皇后的位置从第一个开始模拟,每放置一个皇后,就把能攻击到的位置置为true,然后递归搜索判断第二个皇后的位置,以此类推,直到放下第n个皇后,也就是说,一个新方案产生,然后总个数加一,退出这一层递归继续模拟另外的可能性。如果将皇后放到一半的时候,发现棋盘上已经没有地方能放置皇后,就说明这个方案是不正确的,就直接退出这一层递归,搜索另外的点。
要注意的是,当每层递归结束的时候,也就是撤回皇后的时候,要将原来皇后所侵占的点和所能攻击的线变为false。否则,后果不堪设想(直接翻车!!)!!
              那么代码也就产生了:
#include <bits/stdc++.h>
using namespace std;
int n,sum=0;
bool c[9],d[16],e[17];  //初始化
void queen(int x)
{
       if(x==n+1) //判断当前方案是否成立
       {
              sum++;
              return;
       }
       intj;
       for(j=1;j<=n;j++)  //循环模拟皇后的位置
       {
              if(!c[j] && !d[x-j+n] && !e[x+j]) //判断能否放置皇后
              {
                     c[j]=true;
                     d[x-j+n]=true;
                     e[x+j]=true;
                     queen(x+1);
                     c[j]=false;
                     d[x-j+n]=false;
                     e[x+j]=false;
              }
       }
}
int main()
{
       cin>>n;
       queen(1);  //DFS
       cout<<sum;
       return0;
}
Number 2:整数拆分
题目描述
任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和,求拆分的方案总数和具体的拆分方式。
输入格式     一个整数n
输出格式     一个整数表示方案数,接下来若干行表示方案
样例数据
Input
4
Output
4
n<=暴力一定让你过的数
时间限制:1s
空间限制:256MB
这道题很良心,只需要你输出方案数就行了。
不需要把解给输出出来的话,我们用一个暴力搜索的方法将这个数一个个拆分,再计总个数,输出。
如果当那个被拆分的数n变为零且这个拆分出来的数不是本身的时候,说明出现了一种正确的答案,就把总数加一,然后退出这层递归,去模拟下一种拆分方法。如果出现了负数,也就是说这种拆分方法是不行的,也就退出这层递归,继续模拟寻找另一种可行的拆分方法。
我们要将每一个拆出来的数到一个a数组当中储存下来,每次要拆的数都要从这个数的基础上向当前的拆分后所余下的数这个区间范围内选择,这是为了保证拆出来的方案不会有重复。
    思考一下。
    于是,又可以出代码了:
#include <bits/stdc++.h>
int sum=1,n,m,i,j;
int a[1000];
void f(int k,int x) 
{
    inti;
    if(x==0 && k-1>1)  //判断这个拆分是否成立
    {
       sum++;
       exit;
    }
    for(i=a[k-1];i<=x;i++)  //区间范围循环选择拆分的数
    {
       a[k]=i;
       f(k+1,x-i);  //递归
    }
}
using namespace std;
int main()
{
    cin>>n;
    a[0]=1;
    f(1,n);  //DFS
    cout<<sum;
    return0;
}        DFS还会有很多更难的题目。我只是讲了浅浅的一点,纯粹是入门题,剩下的还需要自己学习,多多刷题。
       微臣告退!  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: