dfs的搜索是基于栈,但一般可以用用递归实现,实际上用的是系统栈。有内部搜索和外部搜索两种,内部搜索是在图的内部,内部搜索一般基于连通性,从一个点转移到另一个点,或者判断是否连通之类的问题,只需要标记避免重复访问即可,不需要还原状态,而外部搜索则是将一张图视为一种状态,每一个状态延伸得到新的状态,要保证每个状态往外延伸时都是相同的,那么就需要还原状态。
搜索顺序也很重要,我们要找到合适的搜索顺序保证不漏的搜出每一种情况,重复当然没什么问题。
另外,同宽搜相比,深搜的代码会简单一些,但是却有爆栈的风险,递归层数比较高的时候需要注意。
1112. 迷宫(活动 - AcWing)
思路:本质上就是判断能不能从这点到达另一点,那么就是连通性问题,深搜宽搜都可以,这里我们用深搜来实现。
#include<bits/stdc++.h>
using namespace std;
int n;
char s[120][120];
int sx,sy,ex,ey;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int st[120][120];
int dfs(int x,int y)
{
if(s[x][y]=='#') return 0;
if(x==ex&&y==ey) return 1;
st[x][y]=1;
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx<0||nx>=n||ny<0||ny>=n) continue;
if(st[nx][ny]) continue;
if(dfs(nx,ny)) return 1;
}
return 0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%s",s[i]);
scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
if(dfs(sx,sy)) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
memset(st,0,sizeof st);
}
}
1113. 红与黑(1113. 红与黑 - AcWing题库)
思路:实际上就是统计一个连通块内有多少个元素。
#include<bits/stdc++.h>
using namespace std;
char g[30][30];
int n,m;
int cnt;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int st[30][30];
void dfs(int x,int y)
{
st[x][y]=1;
cnt++;
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx<0||nx>=n||ny<0||ny>=m) continue;
if(st[nx][ny])continue;
if(g[nx][ny]=='#') continue;
dfs(nx,ny);
}
}
int main()
{
while(scanf("%d%d",&m,&n))
{
if(!n&&!m) break;
for(int i=0;i<n;i++) scanf("%s",g[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(g[i][j]=='@')
{
cnt=0;
dfs(i,j);
cout<<cnt<<endl;
break;
}
memset(st,0,sizeof st);
}
}
1116. 马走日(活动 - AcWing)
思路:这题看似是说在棋盘内部移动,但实际上每次统计一个结果的前提是整个棋盘都被遍历,而且每一步移动有八个选择(理想情况),八个选择各自代表不同的状态,所以我们需要还原状态,只用在最后递归到所有节点都访问过时,记录一下即可。
#include<bits/stdc++.h>
using namespace std;
int n,m;
int st[10][10];
int ans;
int dx[]={1,1,-1,-1,2,2,-2,-2};
int dy[]={2,-2,2,-2,1,-1,1,-1};
void dfs(int x,int y,int k)
{
if(k==n*m)
{
ans++;
return;
}
st[x][y]=1;
for(int i=0;i<8;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx<0||nx>=n||ny<0||ny>=m) continue;
if(st[nx][ny]) continue;
dfs(nx,ny,k+1);
}
st[x][y]=0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int x,y;
scanf("%d%d%d%d",&n,&m,&x,&y);
ans=0;
dfs(x,y,1);
cout<<ans<<endl;
}
}
ps:特殊情况单独判返回的时候一定要注意状态有没有请干净。
1117. 单词接龙(活动 - AcWing)
思路:这里首先要想搜索,我们需要建立单词与单词之间的关系,准确来说我们需要知道哪些单词可以接在哪些单词的后面,它们的重合长度是多少,这里的重合长度一定要越小越好,因为我们可以任意选择重合长度。
那么预处理完之后,直接深搜记录最大值即可。
另外要注意每个单词只能用两次,那么需要记录一下当前单词已经用了几次了,我们可以用下标来实现。
#include<bits/stdc++.h>
using namespace std;
int n;
string s[30];
int used[30];
int g[30][30];
int mx;
void dfs(string r,int k)
{
if(used[k]==2) return;
used[k]++;
for(int i=0;i<n;i++)
{
if(g[k][i]&&used[i]<2)
{
string tmp=r+s[i].substr(g[k][i]);
//cout<<r<<" "<<s[i].substr(g[k][i])<<" "<<g[k][i]<<endl;
mx=max(mx,(int)tmp.size());
dfs(r+s[i].substr(g[k][i]),i);
}
}
used[k]--;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) cin>>s[i];
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
for(int k=1;k<min(s[i].size(),s[j].size());k++)
{
if(s[i].substr(s[i].size()-k,k)==s[j].substr(0,k))
{
g[i][j]=k;
break;
}
}
//printf("%d ",g[i][j]);
}
//printf("\n");
}
char c;
cin>>c;
mx=0;
for(int i=0;i<n;i++)
{
if(s[i][0]==c)
{
mx=max(mx,(int)s[i].size());
dfs(s[i],i);
}
}
cout<<mx;
}
1118. 分成互质组(活动 - AcWing)
思路:如果我们将第一个数放在第一组,那么遍历后面的数,如果不与第一组中的数互质,那么就可以放进这一组,否则就只能新开一组,如此递归来实现,就可保证将所有的数都分好组,同时是分组最少的。
另外由于放进同一个组内的顺序无所谓,所以当不用新开一个组的时候,遍历下一层的时候,直接从后一个元素开始遍历,否则,如果新开组,那么就要从开头开始遍历。因为是按顺序遍历的,所以当前元素被遍历前,它之前的元素与这一组的关系都已经判断过了,所以如果不新开组那么就没必要再往前看。
#include<bits/stdc++.h>
using namespace std;
int n;
int a[20];
int g[20][20];
int ans=10;
int st[20];
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
int check(int u,int g[],int cn)
{
for(int i=0;i<cn;i++)
{
if(gcd(a[u],a[g[i]])>1) return 0;
}
return 1;
}
void dfs(int u,int c,int k,int cn)//u是此时从哪个点开始判断,c是当前处在第几个组,k是已经分配几个点了,cn当前组中有多少个元素
{
if(c>=ans) return;
if(k==n)
{
ans =min(ans,c);
return;
}
int flag=1;
for(int i=u;i<n;i++)
{
if(!st[i]&&check(i,g[c],cn))//一个点都不能放入了再新开
{
st[i]=1;
g[c][cn]=i;
dfs(u+1,c,k+1,cn+1);
st[i]=0;
flag=0;
}
}
if(flag) dfs(0,c+1,k,0);
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
dfs(0,1,0,0);
cout<<ans;
}