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;

}

时间: 2024-11-06 14:54:22

DFS 深度优先搜索例题的相关文章

算法导论——DFS深度优先搜索

package org.loda.graph; import org.loda.structure.Stack; /** * * @ClassName: DFS * @Description: 深度优先搜索(无向图) * @author minjun * @date 2015年5月24日 上午4:02:24 * */ public class DFS { //原点 private int s; // visited[i]表示i节点是否被访问过 private boolean[] visited;

GraphMatrix::DFS深度优先搜索

template <typename Tv, typename Te> //深度优先搜索DFS算法(全图) void Graph<Tv, Te>::dfs(int s) { //assert: 0 <= s < n reset(); int clock = 0; int v = s; //初始化 do //逐一检查所有顶点 if (UNDISCOVERED == status(v)) //一旦遇到尚未发现的顶点 DFS(v, clock); //即从该顶点出发启动一次D

DFS(深度优先搜索)

深度优先搜索算法(Depth-First-Search),是搜索算法的一种.它沿着树的深度遍历树的节点,尽可能深的搜索树的分支.当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点.这一过程一直进行到已发现从源节点可达的所有节点为止.如果还存在未被发现的节点, 则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止.DFS属于盲目搜索. 深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多

回溯 DFS 深度优先搜索[待更新]

首先申明,本文根据微博博友 @JC向北 微博日志 整理得到,本文在这转载已经受作者授权! 1.概念 回溯算法 就是 如果这个节点不满足条件 (比如说已经被访问过了),就回到上一个节点尝试别的路径 也就是说 走到死胡同里边就往回走,直到找到出口. 回溯 是一种 选优搜索 .许多复杂规模较大的问题都可以用 回溯 解决 ,因此回溯法有 "通用解题方法"的美称. 2.思想 若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束.而 若使用回溯法求任一个解时,只要搜

DFS——深度优先搜索的一般格式

DFS是一种深度优先的搜索思想,运用递归完成搜索,本质上也算是穷举思想的一类,可以通过剪枝进行优化. DFS的核心是回溯和递归, 如果以迷宫为例,一般会指定走各个方向的顺序(例如先左再上再右再下).从起点开始,进入DFS(),判断是否到达终点,再判断四个方向是否可走,如果有路,DFS会进入下一格,并且进行同样的判断,此处运用了递归.当四个方向都没路时,就会回溯到上一个位置,继续判断别的方向. DFS用途十分广泛,例如在以二维数组表示的图中搜索路径,也可以用于别的方面,比如求全排列,此时将每个数字

DFS(深度优先搜索遍历有向图)-03-有向图-太平洋大西洋水流问题

给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度.“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界. 规定水流只能按照上.下.左.右四个方向流动,且只能从高到低或者在同等高度上流动. 请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标. 提示: 输出坐标的顺序不重要m 和 n 都小于150 示例: 给定下面的 5x5 矩阵: 太平洋 ~ ~ ~ ~ ~ ~ 1 2 2 3 (5) * ~ 3 2 3 (4) (4) * ~ 2

深度优先搜索学习---(入门)

深度优先搜索的定义 即深度优先是在遍历节点时,以深度为优先,先将一条路遍历完,之后再去遍历别的路. 深度优先的代码框架: 1 /*深度优先*/ 2 3 bool Dfs(V){ 4 if(V为终点) 5 return true; 6 if(v为旧点) 7 return false; 8 将v标记为旧点 9 对和v相邻的每个节点U 10 { 11 if(Dfs(U)==true) 12 13 return true; 14 } 15 return false 16 } 深度优先搜索例题: 解法+思

POJ 1979 Red and Black【深度优先搜索】

题目链接:http://poj.org/problem?id=1979 题目大意:一个矩形的房间地板被分为w*h个小块,每一个小块不是红的就是黑的,你首先站在一个黑色小块上,你只能朝你的四个方向(上下左右)移动,且不能到达红色的小块上,问你最多能到达多少个小块. 很简单的dfs深度优先搜索 没搜索过一个格子,将该格子设置为红色,之后的搜索就不会再搜索到该格子,就不会造成重复,因为该题有很多数据,记得每次处理数据是初始化各数组及其他数据. 代码如下: #include <iostream> #i

代码与算法集锦-归并排序+树状数组+快排+深度优先搜索+01背包(动态规划)

归并排序 求逆序数 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 首先考虑下如何将将二个有序数列合并.这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数.然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可. //将有序数组a[]和b[]合并到c[]中 void MemeryArray(int a[], int n, int b[], int m, int c