搜索(3)dfs的连通性模型和搜索顺序

一、连通性模型

1.

搜索(3)dfs的连通性模型和搜索顺序_第1张图片

 没什么可说的,从起点开始,dfs四周,当到达#时return false,到达终点时return false。

dfs内算法流程应为:赋值st数组,遍历四周(要求在迷宫内且没被搜过),出循环后return false
 

#include
#include
#include
using namespace std;

const int N =110;

int n;
char g[N][N];
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
bool st[N][N];
int xa,ya,xb,yb;


bool dfs(int x,int y)
{
    if(g[x][y]=='#') return false;
    if(x==xb&&y==yb) return true;

    st[x][y]=true;
    for(int i=0;i<4;i++)
    {
        int a=x+dx[i],b=y+dy[i];
        if(a<0||b<0||a>=n||b>=n) continue;
        if(st[a][b]) continue;

        if(dfs(a,b)) return true;
    }
    return false;
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i=0;i>g[i];
        memset(st,false,sizeof st);

        cin>>xa>>ya>>xb>>yb;
        if(dfs(xa,ya)) puts("YES");
        else puts("NO");

    }
    return 0;
}

作者:yankai
链接:https://www.acwing.com/activity/content/code/content/4219882/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2.

搜索(3)dfs的连通性模型和搜索顺序_第2张图片

 从起点开始,dfs四周黑瓷砖。流程:每到一个新的点就res++,并且赋值st数组,然后dfs四周合法位置。遍历完整个搜索树时dfs结束。

#include
#include
#include
using namespace std;

const int N =25;

char g[N][N];
int n,m;
int xa,ya;
int ans;
bool st[N][N];
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};


void dfs(int x,int y)
{
    ans++;
    st[x][y]=true;
    for(int i=0;i<4;i++)
    {
        int a=x+dx[i],b=y+dy[i];
        if(a<0||b<0||a>=n||b>=m) continue;
        if(st[a][b]) continue;
        if(g[a][b]!='.') continue;
        dfs(a,b);
    }
}


int main()
{
    while(cin>>m>>n,n||m)
    {
        for(int i=0;i>g[i][j];
                if(g[i][j]=='@')  xa=i,ya=j;
            }
        ans=0;
        memset(st,false,sizeof st);
        dfs(xa,ya);
        cout<

二、搜索顺序策略

1.

搜索(3)dfs的连通性模型和搜索顺序_第3张图片

 求解:遍历整个棋盘的方案(dfs每次马跳的位置的选择)

分析:从起点dfs,搜索所有位置选择。流程:到一个新的地方,看已经遍历了几个格子,如果是n*m则ans++,并且return。赋值st数组,dfs四周所有没有到达过的合法位置。

略提一下:和前两题不同,本题dfs某个选择之后,要“恢复现场”,消除搜索这个分支带来的影响之后,再搜索下一个分支。

#include
#include
#include
using namespace std;

const int N =11;

bool st[N][N];
int n,m;
int xa,ya;
int ans;
int dx[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
int dy[8] = {1, 2, 2, 1, -1, -2, -2, -1};


void dfs(int x,int y,int cnt)
{
    if(cnt==n*m)
    {
        ans++;
        return ;
    }

    st[x][y]=true;
    for(int i=0;i<8;i++)
    {
        int a=x+dx[i],b=y+dy[i];
        if(a<0||b<0||a>=n||b>=m) continue;
        if(st[a][b]) continue;
        dfs(a,b,cnt+1);
    }
    st[x][y]=false;//回溯 消除这条分支的影响

}



int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n>>m>>xa>>ya;
        memset(st,0,sizeof st);
        ans=0;
        dfs(xa,ya,1);
        cout<

2.

搜索(3)dfs的连通性模型和搜索顺序_第4张图片

 直觉想法:从一个单词开始dfs,选择每一个可以接龙的单词接上(满足接龙接龙条件,并且使用次数不超过2次),接着dfs接上后的单词,直到没有龙可接。为了找出最长龙,设置全局变量ans,每dfs一个新单词时,把当前长度和ans比较即可。

完善:预处理可以接龙的单词和重合部分的长度。注意要回溯现场——used数组

#include
#include
#include
using namespace std;

const int N =25;

string word[N];
int g[N][N];
int used[N];
int n;
int ans;

void dfs(string dragon,int last)
{
    ans=max(ans,(int)dragon.size());
    used[last]++;

    for(int i=0;i>n;
    for(int i=0;i>word[i];
    char start;
    cin>>start;

    for(int i=0;i

3.

搜索(3)dfs的连通性模型和搜索顺序_第5张图片

直觉想法:在组中选择一个数,在剩下的数中继续选择,在遍历的过程中:如果某个数和组内所有数互质的话就加入这个组,然后把这个组的情况深搜下去,如果不互质就跳过。。遍历继续:如果继续遇到其他和这个数互质的,同上,就加入组内然后深搜这个情况。如果遍历结束之后都没有遇到和组内所有数互质的,就开新一个组。

细化:可以实时记录当前已经将多少个数加入组内、开了多少个组。当所有数都加入组内时深搜回溯,记录ans。当当前开的组数大于ans时,直接剪枝。

然后发现需要一个数组记录那些数已经选择过。然后知道我们在回溯时需要“恢复现场”。

本题是组合型枚举,组内的元素顺序并不影响结果。因此如果我们按下标从小到大的顺序枚举,那么我们将第i个数选入组中时,继续深搜时就不必要考虑前i个数,直接从第i+1个数搜起即可。

综上,dfs中需记录:开了几组、这个组内的元素个数(为了方便遍历组内以有元素来判断是否能够将某个数放入组中)、已经搜索过的元素个数、该次dfs可以从哪个数开始搜起。

#include
#include
#include
using namespace std;

const int N =15;
//递归组合型枚举
int  group[N][N];
int n;
bool st[N];
int p[N];
int ans=N;

int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}


bool check(int group[],int gc,int i )
{
    for(int j=0;j1) 
            return false;
    return true;
}

//第几组 组内元素个数 已经搜到的元素个数 组内可以从哪个点开始搜
void dfs(int g,int gc,int tc,int start)
{
    if(g>=ans) return ;
    if(tc==n) ans=g;
    
    bool flag=true;
    for(int i=start;i>n;
    for(int i=0;i>p[i];
    
    dfs(1,0,0,0);
    cout<

你可能感兴趣的:(摆烂日记from,acwing,深度优先,算法)