深搜(DFS)模板

时间:2019-11-16
本文章向大家介绍深搜(DFS)模板,主要包括深搜(DFS)模板使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

当N较小时考虑搜索。

DFS大致模板

    //会有相对应的方向变量  例如: dx[4].dy[4];
void DFS(int x,int y)
{
     if(满足所需要的条件)   {  相应的操作;return;}
    else{
            for(int i= ; ;) //如果是方向的话,会枚举方向
            {
                  枚举加方向的新坐标;
                  if(界限 :例如:不能出到地图外,有障碍,已经访问过) continue;
                   设置已经访问新坐标;
                    DFS(新坐标); 
                   恢复到未被访问;
            }

       }
}  

int main()
{
    //  需注意要将起点设置成已访问。
}  

例题:

P1605  迷宫:

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 int n,m,t;
 5 int StrX,StrY;
 6 int EndX,EndY;
 7 int HndX,HndY;
 8 int dx[4]= {1,-1,0,0};
 9 int dy[4]= {0,0,-1,1};
10 int vis[30][30];
11 int ans;
12 void dfs( int x, int y) //深搜
13 {
14     if(x==EndX &&y==EndY) //一定要把坐标打对!!!!!
15     {
16         ans++;
17         return ;
18     }
19     else
20     {
21         for(int i=0; i<4; i++)
22         {
23             int  NewX=x+dx[i],NewY=y+dy[i];
24             //在这道题中,没有0,0结点,所以NewX<1 NewY<1输出才正确
25             if(NewX>n || NewY>m ||NewX<1 ||NewY<1 || vis[NewX][NewY]==1 ||vis[NewX][NewY]==2)  continue;
26             else
27             {
28                 vis[NewX][NewY]=1;
29                 dfs(NewX,NewY);
30                 vis[NewX][NewY]=0;
31             }
32         }
33     }
34 
35 }
36 int main()
37 {
38     scanf("%d%d%d",&n,&m,&t);
39     scanf("%d%d%d%d",&StrX,&StrY,&EndX,&EndY);
40     while(t--)
41     {
42         scanf("%d %d",&HndX,&HndY);
43         vis[HndX][HndY]=2;  //将障碍设置成2,
44     }
45     vis[StrX][StrY]=1;//将起点1设置成已经访问过的状态!!!!切记 
46     dfs(StrX,StrY);
47     printf("%d",ans);
48 
49     return 0;
50 }

 ------------------------------------------------------------------------------------------------------------------------------------------------------

P1149:火柴棒等式

在这道题中,运用了回溯的思想:

过程是:先将所有的数所需要的火柴数遍历计算出来。然后在Search函数中:根据n-number[i]>=0判断是否还能减去当前火柴数。

如果可以,就将这个数的放入b[]中,载判断是否已经A,B,C,三个数都已经给你找齐,如果找齐的话,再判断是否相等,并且n是否恰好用完。

如果l还不等于3的话,在继续寻找下一个数。

最后保存其初始状态。(比较重要)

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 //使用回溯的方法
 7 int n;
 8 int ans;
 9 int b[4];//存找到的三个数
10 int number[1112]= {6,2,5,5,4,5,6,3,7,6};
11 void Search(int l)
12 {
13     for(int i=0; i<1112; i++)
14     {
15 
16         if(n-number[i]>=0)
17         {
18             b[l]=i;
19             n=n-number[i];
20             if(l==3) //如果符合火柴数的三个数都求出来了,然后判断
21                 {if(b[1]+b[2]==b[3] && n==0) ans++;}
22             else Search(l+1);
23             n=n+number[i];  //不管l是不是等于3,都要保存之前的状态
24           //在这里要特别注意,当判断是否l==3,如果=3,判断
25           //如果!=3,再继续下一个数的搜寻。
26         }
27     }
28 }
29 int main()
30 {
31     scanf("%d",&n);
32     n=n-4;
33     for(int i=10; i<1112; i++) //注意这里是从10开始,不是从0开始。
34     {
35         number[i]=number[i/10]+number[i%10]; //在这里也需要注意,在后面三位数中,分割成一个两位数,和一位数,因为两位数,一位数已经算过了,所以就可以直接加起来
36     }
37     Search(1);
38     printf("%d",ans);
39 }

 ----------------------------------------------------------------------------

P1596 Lake Counting

:这道题是深搜模板题。判断连通图有多少。

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 int n,m,ans;
 5 const int MAXN=105;
 6 char map[MAXN][MAXN];
 7 
 8 void dfs(int x,int y)
 9 {
10     for(int i=-1; i<=1; i++)
11     //在这里一共需要8个方向,循环下来加原点一共9个方向
12     {
13         for(int j=-1; j<=1; j++)
14         {
15             int NewX=x+i,NewY=y+j;
16             if(NewX>=n ||NewY>=m ||NewX<0 || NewY<0 || map[NewX][NewY]=='.')
17                 continue; //判断新的坐标的错,不要打错!!
18             map[NewX][NewY]='.';
19             dfs(NewX,NewY);
20         }
21     }
22     return;
23 }
24 int main()
25 {
26     scanf("%d%d",&n,&m);
27     for(int i=0; i<n; i++)
28         scanf("%s",map[i]);
29     for(int i=0; i<n; i++)
30     {
31         for(int j=0; j<m; j++)
32         {
33             if(map[i][j]=='W')
34             {
35                 map[i][j]='.';
36                 ans++;
37                 dfs(i,j);
38             }
39         }
40     }
41     printf("%d",ans);
42     return 0;
43 }

我出现的问题: 

1.在判断界限时手误打错NewX NewY 和x,y;

2. 因为我读入的时候是从下标0开始的,所以在判断界限时应该是NewX>=n 时就已经越界了;

3.之前一直写成4个方向。在这里是8个方向。

------------------------------------------------------------------------------------------------------------------------------

P1219八皇后

采用DFS

#include <iostream>
#include <cstdio>
using namespace std;
int n,a[14],l[27],r[27],ans[14],js=0; //标记是否相应位置上有皇后
void print()
{
    for(int i=1;i<=n;i++) printf("%d ",ans[i]);
    cout<<endl;
}
void dfs(int i)
{
  if(i>n)
  {
      js++;
      if(js<=3) print();
  }
    for(int j=1;j<=n;j++)
    {
        if(a[j]==0 && l[i+j-1]==0 &&r[i-j+n]==0) 
/*判断界限,当前位置,左对角线,右对角线的*/
        {
            a[j]=1;
            l[i+j-1]=1;
            r[i-j+n]=1;
            ans[i]=j;
            dfs(i+1); 
//恢复初始时的状态 a[j]=0; l[i+j-1]=0; r[i-j+n]=0; } } } int main() { scanf("%d",&n); dfs(1); printf("%d",js); }

对于这道题有几个重要的点:

1.数组大小,

2.判断左对角线和右对角线的公式

3.将答案存储在ans[]数组中

4.输出答案;

------------------------------------------------------------

P1086 花生采摘,采用贪心的方法。

这道题是将所有的可采的花生排序,然后一直找可采的最大的花生。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 using namespace std;
 5 const int MAXN=20;
 6 int map[MAXN][MAXN];
 7 int k,t,m,n,ans,u;
 8 struct node
 9 {
10     int x;
11     int y;
12     int time;
13     int num;
14 }Edge[400];
15 bool cmp(node a,node b)
16 {
17     return a.num>b.num;
18 }
19 void dfs()
20 {
21     for(int i=0; i<k; i++)
22     {
23         u=Edge[i].x+1; //深度
24         if(i==0) Edge[i].time=Edge[i].x+1+1; //第一步的时间等于第一个点的深度+1;因为下标是从0开始,所以要再加1;
25         else Edge[i].time=Edge[i-1].time+abs(Edge[i].x-Edge[i-1].x)
26             +abs(Edge[i].y-Edge[i-1].y)+1; //如果不是第一步的,要算出两个点之间的移动时间,以及采摘时间,以及之前的总时间
27         if(Edge[i].time+u<=t)  {ans+=Edge[i].num;}   //如果采摘花生的过程中花费的时间(包括采摘,走路)加回到原点的时间=约定的时间,则加入花生数。
28     }
29 }
30 int main()
31 {
32     scanf("%d%d%d",&m,&n,&t);
33     for(int i=0; i<m; i++)
34     {
35         for(int j=0; j<n; j++)
36         {
37             scanf("%d",&map[i][j]);
38             if(map[i][j]!=0)
39             {
40                 Edge[k].num=map[i][j];
41                 Edge[k].x=i;
42                 Edge[k].y=j;
43                 k++;
44             }
45         }
46     }
47     sort(Edge,Edge+k,cmp);
48     dfs();
49     printf("%d",ans);
50     return 0;
51 }

原文地址:https://www.cnblogs.com/yangln/p/11833183.html