DFS——连通性和搜索顺序

dfs的搜索是基于栈,但一般可以用用递归实现,实际上用的是系统栈。有内部搜索和外部搜索两种,内部搜索是在图的内部,内部搜索一般基于连通性,从一个点转移到另一个点,或者判断是否连通之类的问题,只需要标记避免重复访问即可,不需要还原状态,而外部搜索则是将一张图视为一种状态,每一个状态延伸得到新的状态,要保证每个状态往外延伸时都是相同的,那么就需要还原状态。

搜索顺序也很重要,我们要找到合适的搜索顺序保证不漏的搜出每一种情况,重复当然没什么问题。

另外,同宽搜相比,深搜的代码会简单一些,但是却有爆栈的风险,递归层数比较高的时候需要注意。

1112. 迷宫(活动 - AcWing)

DFS——连通性和搜索顺序_第1张图片

思路:本质上就是判断能不能从这点到达另一点,那么就是连通性问题,深搜宽搜都可以,这里我们用深搜来实现。

#include
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

1113. 红与黑(1113. 红与黑 - AcWing题库)

DFS——连通性和搜索顺序_第2张图片

思路:实际上就是统计一个连通块内有多少个元素。

#include
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

 1116. 马走日(活动 - AcWing)

DFS——连通性和搜索顺序_第3张图片

思路:这题看似是说在棋盘内部移动,但实际上每次统计一个结果的前提是整个棋盘都被遍历,而且每一步移动有八个选择(理想情况),八个选择各自代表不同的状态,所以我们需要还原状态,只用在最后递归到所有节点都访问过时,记录一下即可。

#include
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<

ps:特殊情况单独判返回的时候一定要注意状态有没有请干净。

1117. 单词接龙(活动 - AcWing)

DFS——连通性和搜索顺序_第4张图片

思路:这里首先要想搜索,我们需要建立单词与单词之间的关系,准确来说我们需要知道哪些单词可以接在哪些单词的后面,它们的重合长度是多少,这里的重合长度一定要越小越好,因为我们可以任意选择重合长度。

那么预处理完之后,直接深搜记录最大值即可。

另外要注意每个单词只能用两次,那么需要记录一下当前单词已经用了几次了,我们可以用下标来实现。

#include
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>s[i];
    for(int i=0;i>c;
    mx=0;
    for(int i=0;i

 1118. 分成互质组(活动 - AcWing)

DFS——连通性和搜索顺序_第5张图片

思路:如果我们将第一个数放在第一组,那么遍历后面的数,如果不与第一组中的数互质,那么就可以放进这一组,否则就只能新开一组,如此递归来实现,就可保证将所有的数都分好组,同时是分组最少的。

另外由于放进同一个组内的顺序无所谓,所以当不用新开一个组的时候,遍历下一层的时候,直接从后一个元素开始遍历,否则,如果新开组,那么就要从开头开始遍历。因为是按顺序遍历的,所以当前元素被遍历前,它之前的元素与这一组的关系都已经判断过了,所以如果不新开组那么就没必要再往前看。

#include
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;i1) 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

 

你可能感兴趣的:(深度优先,算法)