今天,我们又双叒叕没见到我们本该见到的任课老师,可是他带着那些学的比较好的同学私奔转入另外一个班里去了。
然后,我问了一下现在的任课老师,今天学什么。
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数组的空间。
于是,老师急急匆匆地对我们说,他还有点事,于是他就把我们叫出来,自己回去了。。。。