DFS 深度优先搜索例题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DFS 深度优先搜索例题相关的知识,希望对你有一定的参考价值。

  约翰的农场被暴风雨给淹没了,损失很大,他的保险公司将支付给他,但是支付金额取决于被淹没的最大面积。这个农场是一个边长分别为n、m的矩形,包含nm个空间,每个空间要么是干的,要么是被淹没的,一共有k个空间被淹没。求最大的淹没面积。

题目分析:首先建立坐标,标记被淹没的空间,然后从左上角搜索被淹没的空间,并取消标记,再以此为中心向四周搜索是否有被淹没的空间,有的话继续计数并取消标记,以此类推,找出所有被淹没的空间,最后排序,找到被淹没最大的面积。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int a[110][110];
int num[110];
int ans,n,m;
void dfs(int x,int y)  //深度优先搜索
{
  if(a[x][y]==1||x<1||x>n||y<1||y>m)  //判断是否越界,是否是被淹没的
      return ;
   num[ans]++;  //计数
   a[x][y]=1;
   dfs(x-1,y);
   dfs(x+1,y);
   dfs(x,y+1);
   dfs(x,y-1);
}
int main()
{
   int i,j,k,x,y;
   while(~scanf("%d%d%d",&n,&m,&k))
   {
      ans=-1;
      memset(num,0,sizeof(num));  //初始化
      for(i=1;i<=n;i++)  //建立坐标
         for(j=1;j<=m;j++)
            a[i][j]=1;
      while(k--)
      {
         scanf("%d%d",&x,&y);  //标记被淹没的
          a[x][y]=0;
      }
      for(i=1;i<=n;i++)
         for(j=1;j<=m;j++)
         {
          if(a[i][j]==0)  //搜索被淹没的
          {
             ans++;
             dfs(i,j);
          }
     }
    sort(num,num+ans+1);  //快排
    printf("%d\n",num[ans]);
  }
  return 0;
}

题目大意:春天来了,汤姆有一块包含n*m个方块良田,他有一个耕种机器(位于左上角),但是其中有一些方块田地有大石块,机器不能通过,然而他想把没有石块的全部良田耕种,可能吗?

题目分析:首先利用字符串建立地图,找出所以有石块的田地并计数,然后从左上角搜索没有石块的良田并标记计数,然后判断下一块田地是否可以耕种,以此类推,直到不能再耕种,判断所记的数目是否等于所有田地的总数目

  • #include <stdio.h>  
  • #include <string.h>  
  • char str[10][10];  
  • int n,m,sum;  
  • bool flag;  
  • void dfs(int x,int y)       //深度优先搜索   
  • {  
  • if(x<0||x>n-1||y<0||y>m-1||str[x][y]==‘S‘)      //排除不符合条件的   
  • return ;  
  •     sum++;  
  •     str[x][y]=‘S‘;      //标记   
  • if(sum==n*m)        //判断是否可以全部耕种   
  •     {  

        flag=true;  

  • return ;  
  •     }  
  •     dfs(x-1,y);  
  •     dfs(x+1,y);  
  •     dfs(x,y-1);  
  •     dfs(x,y+1);  
  •     sum--;  
  •     str[x][y]=‘.‘;  
  • }  
  • int main()  
  • {  
  • int i,j;  
  • while(scanf("%d%d",&n,&m),n||m)  
  •     {  
  •         sum=0;  
  •         flag=false;  
  • for(i=0;i<n;i++)     //利用字符串输入,省时   
  •             scanf("%s",&str[i]);  
  • for(i=0;i<n;i++)     //找出有石块的田地   
  • for(j=0;j<m;j++)  
  • if(str[i][j]==‘S‘)  
  •                     sum++;  
  •         dfs(0,0);  
  • if(flag)  
  •             puts("YES");  
  • else  
  •             puts("NO");  
  •     }  
  • return 0;  

}  

从 k数组中选择 6 个元素的组合,写出所有的可能情况。

题目分析:其实这个题目有个不好处理的就是最后一个案例不能有换行。把案例看成以文件读入读出,第一个输出不换行,第二个输入再换行。递归实现从 n 个元素中选择 m  个元素,常规法.从头到尾一个一个的找(深度优先搜寻),并递归替换。

#include <stdio.h>  

  • #include <string.h>  
  • int a[50],b[7];  
  • int n;  
  • void dfs(int top,int sum)       //深度优先搜索   
  • {  
  •     if(sum>=6)       //满足条件输出   
  •     {  
  •         for(int i=0;i<6;i++)  
  •         {  
  •             if(i)  
  •                 printf(" ");  
  •             printf("%d",b[i]);  
  •         }  
  •         puts("");  
  •         return ;  
  •     }  
  •     for(int i=top;i<n;i++)       //不满足条件继续搜索   
  •     {  
  •         b[sum]=a[i];  
  •         dfs(i+1,sum+1);       
  •     }  
  •     return ;  
  • }  
  •   
  • int main()  
  • {  
  •     int j;  
  •     while(scanf("%d",&n),n)  
  •     {  
  •         if(j++)     //输出空行   
  •             puts("");  
  •         for(int i=0;i<n;i++)  
  •             scanf("%d",&a[i]);  
  •         dfs(0,0);  
  •     }  
  •     return 0;  
  • }  

变形课上Harry碰到了一点小麻烦,因为他并不像Hermione那样能够记住所有的咒语而随意的将一个棒球变成刺猬什么的,但是他发现了变形咒语的一个统一规律:如果咒语是以a开头b结尾的一个单词,那么它的作用就恰好是使A物体变成B物体。现在将他所会的所有咒语都列成了一个表,他想让你帮忙计算一下他是否能完成老师的作业,将一个B(ball)变成一个M(Mouse)。

题目分析:首先搜索首字母为“B”的单词,然后标记已搜索过,再搜索首字母为上一个单词的尾字母并标记,直到找到尾字母为“M”的单词,输出“Yes.”,如果搜索不到此单词输出“No.”。

#include <stdio.h>  

  • #include <string.h>  
  • #include <algorithm>  
  • using namespace std;  
  •   
  • int vis[1000];  
  • int flag,k;  
  •   
  • struct node     //构建结构体,分别记录单词的首字母和尾字母   
  • {  
  •     int start;  
  •     int end;  
  • }word[1000];  
  •   
  • void dfs(char c)        //深度优先搜索   
  • {  
  •     char temp;  
  •     if(c==‘m‘)      //判断是否找到字母“M”   
  •     {  
  •         flag=1;  
  •         return ;  
  •     }  
  •     for(int i=1;i<k;i++)  
  •         if(vis[i]==0&&word[i].start==c)     //单词没有被搜索过,并且首字母为上一个字母的尾字母   
  •         {  
  •             temp=c;  
  •             c=word[i].end;  
  •             vis[i]=1;       //对于搜索过的单词进行标记   
  •             dfs(c);  
  •             c=temp;  
  •         }  
  • }  
  •   
  • int main()  
  • {  
  •     int i,len;  
  •     char a[100];  
  •     k=1;        //初始化   
  •     while(gets(a)!=NULL)  
  •     {  
  •         if(strcmp(a,"0")==0)        //判断是否输入结束   
  •         {  
  •             flag=0;  
  •             dfs(‘b‘);       //搜索首字母为“b” 的单词   
  •             if(flag)  
  •                 puts("Yes.");  
  •             else  
  •                 puts("No.");  
  •             k=1;        //初始化   
  •         }  
  •         else  
  •         {  
  •             len=strlen(a);  
  •             word[k].start=a[0];  
  •             word[k].end=a[len-1];  
  •             vis[k]=0;  
  •             k++;  
  •         }  
  •     }  
  •     return 0;  
  • }  

在有若干个城墙的n*n的城市里建立大炮,大炮威力很大,除了城墙都能打透,所以两门大炮不能在同一行,或同一列,除非中间有城墙隔着,问最多能建立多少个大炮。

题目分析:从左上角开始搜索,判断是否能安排大炮(此位置的上方和左方不能有大炮,除非有城墙隔着),能安排大炮就标记并统计大炮数目,以此类推,直到所有地方不能安排大炮,输出最多安排大炮的数量。

#include <stdio.h>  

  • #include <string.h>  
  • #include <algorithm>  
  • using namespace std;  
  • char str[5][5];  
  • int t,sum;  
  • bool vis(int x,int y)       //判断此位置的上方,左方是否有大炮或者城墙   
  • {  
  •     int i;  
  •     for(i=x-1;i>=0;i--)  
  •     {  
  •         if(str[i][y]==‘0‘)  
  •             return false;  
  •         if(str[i][y]==‘X‘)  
  •             break;  
  •     }  
  •     for(i=y-1;i>=0;i--)  
  •     {  
  •         if(str[x][i]==‘0‘)  
  •             return false;  
  •         if(str[x][i]==‘X‘)  
  •             break;  
  •     }  
  •     return true;  
  • }  
  • void dfs(int x,int y)  
  • {  
  •     int a,b;  
  •     if(x==t*t)      //是否已经全部搜索完毕   
  •     {  
  •         if(y>sum)        //sum为最多大炮数量   
  •         {  
  •             sum=y;  
  •             return ;  
  •         }  
  •     }  
  •     else  
  •     {  
  •         a=x/t;      //a为行数   
  •         b=x%t;      //b为列数   
  •         if(str[a][b]==‘.‘&&vis(a,b))        //判断此位置是否为空地   
  •         {  
  •             str[a][b]=‘0‘;      //标记已安排大炮   
  •             dfs(x+1,y+1);       //搜索数目和安排的大炮数目分别+1   
  •             str[a][b]=‘.‘;  
  •         }  
  •         dfs(x+1,y);     //搜索数目+1   
  •     }  
  • }  
  • int main()  
  • {  
  •     int i;  
  •     while(scanf("%d",&t)&&t)  
  •     {  
  •         sum=0;  
  •         for(i=0;i<t;i++)     //输入地图   
  •             scanf("%s",str[i]);  
  •         dfs(0,0);       //从左上角开始搜索   
  •         printf("%d\n",sum);  
  •     }  
  •     return 0;  
  • }  

用自己已有的卡片等价交换自己想要的卡片,一共有多少种交换方法。

题目分析:首先将自己所拥有的卡片的价值和数量输入并保存在结构体中,然后进行卡片交换,记录一共有多少种符合等价交换的交换方式

#include <stdio.h>  

  • #include <string.h>  
  • #include <algorithm>  
  • using namespace std;  
  • int sum,m;  
  • struct note     //建立结构体   
  • {  
  •     int value;  
  •     int num;  
  • }a[11];  
  • void dfs(int x,int y,int z)     //深度优先搜索   
  • {  
  •     if(y==z)        //符合条件   
  •     {  
  •         sum++;  
  •         return ;  
  •     }  
  •     if(y>z||x==m)        //价值超出,不符合条件   
  •         return ;  
  •     for(int j=0;j<=a[x].num;j++)  
  •         dfs(x+1,y+j*a[x].value,z);      //递归   
  • }  
  • int main()  
  • {  
  •     int n,i,b=-1;  
  •     while(~scanf("%d%d",&n,&m))  
  •     {  
  •         for(i=0;i<m;i++)  
  •             scanf("%d%d",&a[i].value,&a[i].num);  
  •         b++;  
  •         if(b)  
  •             puts("");  
  •         sum=0;  
  •         dfs(0,0,n);  
  •         printf("%d\n",sum);  
  •     }  
  •     return 0;  
  • }  

设有一个背包可以放入的物品重量为S,现有n件物品,重量分别是w1,w2,w3,...,wn。问能否从这n件物品中选择若干件放入背包中,使得放入的重量之和正好为S。如果有满足条件的选择,则此背包有解,否则此背包问题无解。第一行为物品重量S(整数); 第二行为物品数量n,  第三行为n件物品的重量的序列。

有解就输出”yes!“,没有解就输出”no!“。

#include <iostream>

#include <cstring>

using namespace std;

int wsum = 0;//背包里总重量

int flag = 0;//旗帜法

int book[100];//标记法

void DFS(int S, int m, int w[])//深搜算法

{  

  if (wsum == S)  

  { 

     flag = 1;   

     return;

   }  

  else

  {   

    for (int i = 0; i < m; i++)   

    {   

       if (book[i] == 0)    

      {     

        wsum += w[i];     

        book[i] = 1;     

        DFS(S, m, w);     

        wsum -= w[i];     

        book[i] = 0;    

       }   

    }  

  }  

  return;

}

int main()

{  

  memset(book, 0, sizeof(book));  

  int w[100];  

  int S, m;  

  cin >> S >> m;  

  for (int i = 0; i < m; i++)   

    cin >> w[i];  

  DFS(S, m, w);  

  if (flag == 1)   

    cout << "yes!";  

  else  

     cout << "no!";

   return 0;

}

 

 

 

以上是关于DFS 深度优先搜索例题的主要内容,如果未能解决你的问题,请参考以下文章

Python算法-深度优先搜索&广度优先搜索(DFS&BFS)

算法笔记8.1 深度优先搜索DFS

深度搜索(dfs)+典型例题(八皇后)

通过迷宫问题简单学习DFS和BFS算法

通过迷宫问题简单学习DFS和BFS算法

通过迷宫问题简单学习DFS和BFS算法