深度优先搜索

今天,我们又双叒叕没见到我们本该见到的任课老师,可是他带着那些学的比较好的同学私奔转入另外一个班里去了。

然后,我问了一下现在的任课老师,今天学什么。

He said,"We study the DFS(深度优先搜索)today."

于是,我想到在童程童美学习DFS的场景,又想到了NOIP普及组遇到搜索傻傻愣着不会做的场景。。。

于是,我选择了呆在这里继续学习。。。

先上深度优先搜索的定义:

深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次.

精益求精的大佬们可以直接看:https://baike.so.com/doc/5851274-6064113.html

深度优先搜索100%要用到递归,否则为哈子《信息学奥赛一本通初级篇》里讲深搜的章节的标题叫做搜索与回溯呢?

深度优先搜索的代码结构是这样的:

int dfs(int depth){

    所有下一步可能的地方的循环{

if(没到边界){

        搜索;

        回溯;

}

    }

}

然后老师让我们做一本通上的《八皇后》。http://ybt.ssoier.cn:8088/problem_show.php?pid=1214

整体思路是这样的:

先把八皇后所有的可能情况遍历完,再让题目里的个例序号对号入座。可以用传统的二维数组,也可以用我上一秒才想到的结构体数组。

但因为我不会懒,所以采用二维数组。

首先在dfs里面保证新的一个皇后不与前面的任意一个皇后同行,也不让与任意一个皇后同列。

然后在最后检查输出的part再考虑对角线的问题。

参考代码如下:

#include<bits/stdc++.h>
using namespace std;
int n,a[11],map1[11],sum,b[93][9];
int print(){
	for(int i=1;i<=8;i++){
		for(int j=i+1;j<=8;j++){
			if(abs(i-j)==abs(a[i]-a[j])) return 0;//保证对角线上没有一样的 
		}
	}
	sum++;
	for(int i=1;i<=8;i++){
		b[sum][i] = a[i];
	}
	return 0;
}
int dfs(int deep){
	if(deep>8){
		//选完了 
		print();
		return 0;
	}
	for(int i=1;i<=8;i++){
		if(map1[i]==0){
			//选 
			map1[i]=1;
			a[deep]=i;
			dfs(deep+1);
			//还原 
			a[deep]=0;
			map1[i]=0;
		}
	}
	return 0;
}
int main(){
	cin>>n;
	dfs(1);
	for(int i=0;i<n;i++){
		int c;
		cin>>c;
		for(int j=1;j<=8;j++){
			cout<<b[c][j];
		}
		cout<<endl;
	}
	return 0;
}

然后做water题:组合的输出http://ybt.ssoier.cn:8088/problem_show.php?pid=1317

思路是这样的:

从一开始遍历,遍历到n;depth从一开始,当depth==r时,返回

如果上一个小于当前数,则把当前数记录在数组里。

参考代码如下:

#include<bits/stdc++.h>
using namespace std;
int a[22],n,r;
int print(){
	for(int i=1;i<=r;i++) cout<<"  "<<a[i];
	cout<<endl;
}
int dfs(int deep){
	if(deep>r){
		print();
		return 0;
	}
	for(int i=1;i<=n;i++){
		if(a[deep-1]<i){
			a[deep]=i;
			dfs(deep+1);
			a[deep]=0;
		}
	}
}
int main(){
	cin>>n>>r;
	dfs(1);
	return 0;
}

最后做LETTERShttp://ybt.ssoier.cn:8088/problem_show.php?pid=1212

思路如下:

更新最大值,先for出下一步能到达的地方的坐标,如果下一个地方没走过,且字母没见到过,那么就暂时走到那个地方,继续dfs。最后输出一下最大值就行了。

参考代码如下:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define N 30
using namespace std;
int r,s;
char a[N][N];
int vis[N][N];
int num[26];
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int maxx=0;
void dfs(int x,int y,int step)
{
    if(maxx<step)
        maxx=step;
    for(int i=0;i<4;i++)
    {
        int nx=x+dir[i][0];
        int ny=y+dir[i][1];
        if(nx>=0&&nx<r&&ny>=0&&ny<s&&vis[nx][ny]==0&&num[a[nx][ny]-'A']==0)
        {
            vis[nx][ny]=1;
            num[a[nx][ny]-'A']=1;
            dfs(nx,ny,step+1);
            vis[nx][ny]=0;
            num[a[nx][ny]-'A']=0;
        }
    }
}
int main()
{
    cin>>r>>s;
    for(int i=0;i<r;i++)
        for(int j=0;j<s;j++)
            cin>>a[i][j];
    num[a[0][0]-'A']=1;
    vis[0][0]=1;
    dfs(0,0,1);
    cout<<maxx<<endl;
    return 0;
}

其实嘛,如果这个地方被探测到了,那么字母也就被探测到了,所以只需要判断子母的问题就行了,还可以省下来一个vis数组的空间。

于是,老师急急匆匆地对我们说,他还有点事,于是他就把我们叫出来,自己回去了。。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值