DFS & BFS

DFS

int DFS(int t)
{
    if(满足输出条件)
    {
        输出解;
    }
    else
    {
        for(int i=1;i<=尝试方法数;i++)
            if(满足进一步搜索条件)
            {
                为进一步搜索所需要的状态打上标记;
                DFS(t+1);
                恢复到打标记前的状态;//也就是说的{回溯一步}
            }
    }
}

整个模板有几个地方需要注意:
1.第一个if是符合输出解的条件,第二个if是符合进一步搜索的条件;

2.下一步搜索时,不是使用return search(t+1),直接search(t+1);(新手可能会注意不到这个关键的地方,以至于每次写完不知道为什么只得到一个答案就返回主程序了)

3.for循环之后的if可以是多个;

4.for循环边界,例如:

1>方向是四个,那么边界肯定就是4;(帖主用3,是因为从0开始的)

2>素数环需要尝试1至20,那么边界就是20;

油田问题Oil Deposits(DFS)

Description

GeoSurvComp地质调查公司负责探测地下石油储藏。 GeoSurvComp现在在一块矩形区域探测石油,并把这个大区域分成了很多小块。他们通过专业设备,来分析每个小块中是否蕴藏石油。如果这些蕴藏石油的小方格相邻,那么他们被认为是同一油藏的一部分。在这块矩形区域,可能有很多油藏。你的任务是确定有多少不同的油藏。

Input
输入可能有多个矩形区域(即可能有多组测试)。每个矩形区域的起始行包含m和n,表示行和列的数量,1<=n,m<=100,如果m =0表示输入的结束,接下来是n行,每行m个字符。每个字符对应一个小方格,并且要么是’*’,代表没有油,要么是’@’,表示有油。

Output
对于每一个矩形区域,输出油田的数量。两个小方格是相邻的,当且仅当他们水平或者垂直或者对角线相邻(即8个方向)。

题解

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<iostream>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define maxn 1000500
using namespace std;
typedef unsigned long long LL;
char a[105][105];
int mov[8][2]={1,0,-1,0,0,1,0,-1,1,1,-1,-1,1,-1,-1,1};
int m,n;
void dfs(int x,int y)
{
    int nextx,nexty,i;
    a[x][y]='*';
    for(i=0;i<8;i++)
    {
        nextx=x+mov[i][0];
        nexty=y+mov[i][1];
        if(nextx>=0 && nextx<m && nexty>=0 && nexty<n)
        {
            if(a[nextx][nexty]=='@')
            {
                dfs(nextx,nexty);
            }
        }
    }
}

int main()
{
	while(~scanf("%d%d",&m,&n))
	{
		if(m==0 || n==0) break;
		int i,j,sum=0;
		for(i=0;i<m;i++)
			for(j=0;j<n;j++)
                scanf(" %c",&a[i][j]);
		for(i=0;i<m;i++)
		{
			for(j=0;j<n;j++)
			{
				if(a[i][j]=='@')
                {
                    dfs(i,j);
                    sum++;
                }
			}
		}
		printf("%d\n",sum);
	}
	return 0;
}

例题:迷宫问题(DFS)

给定一个N*M方格的迷宫,迷宫里有T处障碍,障碍处不可通过。给定起点坐标和

终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案。在迷宫

中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。

输入样例 输出样例

【数据规模】

1≤N,M≤5

题目描述
输入输出格式
输入格式:
【输入】

第一行N、M和T,N为行,M为列,T为障碍总数。第二行起点坐标SX,SY,终点

坐标FX,FY。接下来T行,每行为障碍点的坐标。

输出格式:
【输出】

给定起点坐标和终点坐标,问每个方格最多经过1次,从起点坐标到终点坐标的方

案总数。

输入输出样例
输入样例#1: 复制
2 2 1
1 1 2 2
1 2
输出样例#1: 复制
1

题解

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<iostream>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define maxn 1000500
using namespace std;
typedef unsigned long long LL;
int a[105][105]; //地图
int temp[105][105]; //走过的标记
int mov[4][2]={1,0,-1,0,0,1,0,-1}; //前后左右走
int m,n,t,sx,sy,fx,fy,l,r,nextx,nexty,total=0;
void dfs(int x,int y)
{
    if(x==fx && y==fy)
    {
        total++;
        return;
    }
    else
    {
        for(int i=0;i<4;i++)
        {
            nextx=x+mov[i][0]; 
            nexty=y+mov[i][1];//下一步 
            if(temp[nextx][nexty]==0 && a[nextx][nexty]==1)
            {
                temp[x][y]=1; //标记已走
                dfs(nextx,nexty);
                temp[x][y]=0; //回溯
            }
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&t);
	for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j]=1;
	scanf("%d%d",&sx,&sy);
	scanf("%d%d",&fx,&fy);
	for(int i=1;i<=t;i++)
    {
        scanf("%d%d",&l,&r);
        a[l][r]=0; //标记障碍
    }
    dfs(sx,sy);
    printf("%d\n",total);
	return 0;
}

洛谷P1162 填涂颜色(DFS)
题目描述
由数字01组成的方阵中,有一任意形状闭合圈,闭合圈由数字1构成,围圈时只走上下左右4个方向。现要求把闭合圈内的所有空间都填写成2.例如:6×6的方阵(n=6),涂色前和涂色后的方阵如下:

0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1

0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1

题解
染色法,把全部的0染色成2。然后从外围DFS,将外面的0全部标记。记得在最外围加一圈0,这样外围才可以DFS全部的0,。

代码

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<iostream>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define maxn 1000500
using namespace std;
typedef unsigned long long LL;
int a[105][105]; //染色
int b[105][105]; //地图
int mov[4][2]={1,0,-1,0,0,1,0,-1};
int n,nextx,nexty;
void dfs(int x,int y)
{
    if(x<0 || x>n+1 || y<0 || y>n+1 || a[x][y]!=0)
        return;
    a[x][y]=1;//染色
    for(int i=0;i<4;i++)
    {
        nextx=x+mov[i][0];
        nexty=y+mov[i][1];
        dfs(nextx,nexty);
    }
}

int main()
{
    scanf("%d",&n);
	for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            scanf("%d",&b[i][j]);
            if(b[i][j]==0)
                a[i][j]=0;
            else
                a[i][j]=2;
        }
    dfs(0,0);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
        if(a[i][j]==0)
            printf("2 ");
        //如果染过色以后i,j那个地方还是0,说明没有搜到,就是周围有墙,当然就是被围住了
        else
            printf("%d ",b[i][j]);
        //因为被染色了,本来没有被围住的水和墙都染成了1,所以就输出b[i][j]
    }
        printf("\n");
    }
	return 0;
}

八皇后(DFS)

检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下:

行号 1 2 3 4 5 6

列号 2 4 6 1 3 5

这只是跳棋放置的一个解。请编一个程序找出所有跳棋放置的解。并把它们以上面的序列方法输出。解按字典顺序排列。请输出前3个解。最后一行是解的总个数。

输入输出格式
输入格式:
一个数字N (6 <= N <= 13) 表示棋盘是N x N大小的。

输出格式:
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

输入输出样例
输入样例#1: 复制
6
输出样例#1: 复制
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4

题解

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<iostream>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define maxn 1000500
using namespace std;
typedef unsigned long long LL;
int a[100];//行
int b[100];//列
int c[100];//左下到右上的对角线
int d[100];//左上到右下的对角线
int total=0,n;

void dfs(int i)
{
    if(i>n)
    {
        if(total<=2) //只要前三个解
        {
            for(int k=1;k<=n;k++)
                printf("%d ",a[k]);
                printf("\n");
        }
        total++;
    }
    else
    {
        for(int j=1;j<=n;j++)   //尝试可能的位置
        {
            if(b[j]==0 && c[i+j]==0 && d[i-j+n]==0) //未被占领
            {
                a[i]=j;      //标记第i排是第j个
                b[j]=1;      //占领该列
                c[i+j]=1;    //占领左下到右上的对角线
                d[i-j+n]=1; //占领左上到右下的对角线
                dfs(i+1); //搜索下一行
                //回溯 回到上一步 清除标记
                b[j]=0;      //解放该列
                c[i+j]=0;    //解放左下到右上的对角线
                d[i-j+n]=0; //解放左上到右下的对角线
            }
        }
    }
}

int main()
{
   scanf("%d",&n);
   dfs(1);
   printf("%d\n",total);
}

例题:n个数,每个数有一个,判断是否可以选一些数,使得和为k

    #include<stdio.h>
    #include<stdlib.h>
    #include<math.h>
    #include<string.h>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<stack>
    #include<map>
    #define exp 1e-9
    #define PI acos(-1.0)
    #define INF 0x3f3f3f3f
    using namespace std;
    int a[20];
    int n,k;
    bool dfs(int i,int sum)
    {
        //搜索完毕
        if(i==n)    return k==sum;
        //不加上a[i]
        if(dfs(i+1,sum)) return true;
        //加上a[i]
        if(dfs(i+1,sum+a[i])) return true;
        return false;
    }
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        if(dfs(0,0))
            printf("YES\n");
        else
            printf("NO\n");
        return 0;
    }

n个数a[i],每个数有b[i]个,判断是否能选一些数使得和为K

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
using namespace std;
typedef pair<int,int> p;
typedef long long LL;
int n,k;
int a[105],b[105];
bool dp[105][105];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
        scanf("%d",&b[i]);
    memset(dp,false,sizeof(dp));
    dp[0][0]=true;
    for(int i=0;i<=n;i++)
        for(int j=0;j<=k;j++)
            for(int kk=0; (kk<=b[i]) && (kk*a[i]<=j) ;kk++)
                dp[i+1][j]|=dp[i][j-a[i]*kk];
    if(dp[n][k])
        printf("YES\n");
    else
        printf("NO\n");
	return 0;
}

BFS

迷宫问题

S为起点,G为终点,#为墙,*为路,求S到G最短距离

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
using namespace std;
typedef pair<int,int> p; //这样用更方便
char a[105][105];
int d[105][105];
int ma[4][2]={0,1,0,-1,1,0,-1,0};
int n,m,sx,sy,fx,fy;
int bfs()
{
    queue<p>q;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            d[i][j]=INF;
    q.push(p(sx,sy));
    d[sx][sy]=0;
    while(q.size())
    {
        
        p pp;
        pp=q.front(); q.pop(); //从队列最上端取出元素
        if(pp.first==fx && pp.second==fy) break; //找到
        for(int i=0;i<4;i++)
        {
            int nx=pp.first+ma[i][0];
            int ny=pp.second+ma[i][1];
            if(nx>=1 && nx<=n && ny>=1 && ny<=m && a[nx][ny]!='#' && d[nx][ny]==INF)
            {
                q.push( p(nx,ny) ); //继续
                d[nx][ny]=d[pp.first][pp.second]+1; //距离加1
            }
        }
    }
    return d[fx][fy];
}
int main()
{
    int ans;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf(" %c",&a[i][j]);
            if(a[i][j]=='S')
            {
                sx=i;
                sy=j;
            }
            if(a[i][j]=='G')
            {
                fx=i;
                fy=j;
            }
        }
    ans=bfs();
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值