浅谈深度优先搜索

最近几天在洛谷上练习搜索类的题目,虽然效率极其低下,但慢慢还是摸索出一些深度及广度搜素的套路。现在来总结几道深度优先搜索的模板题。

1、经典的八皇后问题:

输入:方阵的大小n,

输出:前三行输出前三种方式(每行的皇后的列标),第四行输出方法总数;

思想:以列为单位放置皇后,放置一个皇后之后,标记上此皇后所在行、两条斜线;下一次放置之前则先判断当前所在行、两条斜线有没有被标记;此题需要搞清楚所在两条斜线的坐标特点。右上的斜线上每个点所在横纵坐标之和都相等;左下的斜线横纵坐标之差相等。因此此题需要用三种不同的标记。

题目代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 bool flag[4][50]={0};//flag[1]代表所在行被标记,flag[2]代表右下斜线,flag[3]标记左上的斜线 
 4 int n,sum=0;//n代表方阵大小,sum代表解法的总数 
 5 int ans[50];//保存每次选择的列坐标 
 6 
 7 void dfs(int i){
 8     int j;
 9     if(i>n){//所有列都访问完即为一种方法 
10          ++sum;
11          if(sum>3)return ;
12          else
13          {
14          for(int i=1;i<=n;++i)
15          printf("%d ",ans[i]);
16          printf("\n");
17          return ;
18            }
19     }
20     for(j=1;j<=n;j++){
21         if(!flag[1][j] && !flag[2][i+j] && !flag[3][i-j+n]){//所在行、两边的斜线都没有被标记才能选 
22             ans[i]=j;
23             flag[1][j]=1;
24             flag[2][i+j]=1;
25             flag[3][i-j+n]=1;
26             dfs(i+1);
27             //回溯,取消标记 
28             flag[1][j]=0;
29             flag[2][i+j]=0;
30             flag[3][i-j+n]=0;    
31         }
32     }
33 }
34 
35 int main(){
36     cin>>n;
37     dfs(1);
38     cout<<sum;
39     return 0;
40 }
八皇后问题

 

2、单词方阵问题

输入格式

第一行输入一个数nnn。(7n100)。

第二行开始输入n×n的字母矩阵。

输出格式

突出显示单词“yizhong”的n×n矩阵。

解题思路:找出每一个'y'出现的位置,从此处开始四个方向开始寻找可匹配下一个单词的地方,找到则沿着这条路继续走,找不到则返回到最初的起点,换下一条路,此题不需标记上一步走过的位置,但需要把每一步符合要求的坐标都保存在另一个数组里做上标记,便于最后的输出。

解题代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 struct node{
 4     int x,y;//每个字符所在的横纵坐标 
 5 }c[120];
 6 
 7 int n;
 8 string st = "yizhong";
 9 char s[120][120];
10 int visit[120][120]={0};
11 int next1[][2]={1,0,1,1,1,-1,-1,0,-1,1,-1,-1,0,1,0,-1};
12 
13 void dfs(int x,int y,int k,int cur){
14 
15     if(cur>=7){
16         for(int i=0;i<7;i++)
17             visit[c[i].x][c[i].y]=1;
18     }
19       
20     else {
21         int dx=x+next1[k][0];
22         int dy=y+next1[k][1];
23         if(cur==6||s[dx][dy]==st[cur+1] ){
24             c[cur].x=x;c[cur].y=y;
25             dfs(dx,dy,k,cur+1);
26 
27         }
28     }
29 }
30 
31 int main(){
32     cin>>n;
33     for(int i=0;i<n;i++)
34      for(int j=0;j<n;j++)
35         cin>>s[i][j];
36     
37          
38     for(int i=0;i<n;i++)
39       for(int j=0;j<n;j++)
40         if(s[i][j]=='y')
41            for(int k=0;k<8;k++){
42             int x=i+next1[k][0];
43             int y=j+next1[k][1];
44             if(s[x][y]=='i')
45             dfs(i,j,k,0);
46         }
47     
48     for(int i=0;i<n;i++){
49     for(int j=0;j<n;j++){
50         if(visit[i][j]==1)cout<<s[i][j];
51         else cout<<"*";
52     } 
53     cout<<endl;
54     }
55     return 0;
56     }
单词矩阵

结果展示:

3、单词接龙 

解题思路:首先需要找到每个单词之间的最小公共部分(有公共部分的才能连接起来),从第一个单词开始进行深搜,记录每次结果的长度,选择最大长度输出。

代码实现:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int aga[25][25];
 4 int n,len=0,mlen=-1;
 5 string s[21];
 6 char ch;
 7 int visit[25]={0};
 8 
 9 int check(int i,int j){//找到单词之间的最小公共部分 
10     int kj=0;
11     int f=1;
12         for(int k=s[i].size()-1;k>=0;k--){
13         for(int ki=k;ki<s[i].size();ki++){
14             if(s[i][ki]!=s[j][kj++]){//第一个字符不匹配 ,前面字符串调到上一个,后面字符串回到第一个 
15             f=0;
16             break;
17             }
18         }
19         if(f==1)//匹配成功 
20         return s[i].size()-k;
21         kj=0;
22         f=1;
23         } 
24         return 0; 
25         }
26 
27 int dfs(int i)//参数为字符串的序号
28 {
29 
30     int f=0;
31     for(int j=0;j<n;j++){
32         if(visit[j]>=2)continue;//访问次数超过为2 
33         if(aga[i][j]<1)continue;//没有重叠部分 
34         if(aga[i][j]==s[i].size() || aga[i][j]==s[j].size())continue;//重叠部分包含单词本身的情况
35         f=1;
36         len+=s[j].size()-aga[i][j];
37         visit[j]++;
38         dfs(j);
39         len-=s[j].size()-aga[i][j];//回溯
40         visit[j]--; 
41     }
42     if(f==0)//到达龙 的结尾,保存长度 
43     mlen=max(len,mlen);//保存“龙”最长时候的长度; 
44     return 0;
45  } 
46  int main(){
47      cin>>n;
48      for(int i=0;i<n;i++){
49          cin>>s[i];
50      }
51      cin>>ch;
52      for(int i=0;i<n;i++)
53          for(int j=0;j<n;j++)
54              aga[i][j]=check(i,j);
55     for(int i=0;i<n;i++){
56         if(s[i][0]==ch&&s[i].size()>1)
57         {
58             visit[i]++;
59             len=s[i].size();
60             dfs(i);
61             visit[i]=0;
62         }
63     }
64     cout<<mlen;
65     return 0;     
66  } 
单词接龙

 

深搜可以记录每一次搜索的结果,适用于解答需答题目要求多种解的类型,在很多题型中深搜也结合记忆化搜索在运用,做题时需要灵活思考,不能死套模板

 

 

 

转载于:https://www.cnblogs.com/SUHANG12138/p/11385672.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值