• DFS,BFS回顾(各种题)(肺炎疫情中,祝平安)


          基础知识:

              queue队列的相关用法:先进先出(FIFO)

                                                         入队push()   //即插入元素

                                                         出队pop()    //即删除元素

                                                         front()        //读取队首元素

                                                         back()       //读取队尾元素

                                                         empty()     //判断队列是否为空

                                                         size()        //读取队列当前元素的个数         

        ————————————————————————————————————————————————————————————————————————

          POJ 3278

          一个人在n点,牛在k点,这个人有两种移动方式,+1,-1,*2;移一下就是一分钟。问最短时间?

          典型的BFS,,一个发散式的搜索,对于每个点,找出其可以到达的下三个点,第一个到达k的,此为最快,输出所需时间即可。

          

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    const int maxn = 1e5 +10;
    int st[maxn];
    bool vis[maxn];
    using namespace std;
    queue<int>q;
    void first()
    {
            memset(st,0,sizeof(st));
            memset(vis,false,sizeof(vis));
            while(!q.empty())
            {
                q.pop();  //记得初始化队列
            }
    }
    int bfs(int n,int k)
    {
        int head,next;
        q.push(n);
        st[n]=0;
        vis[n]=true;
        while(!q.empty())
        {
            head=q.front();  //取头
            q.pop();      //去头
            for(int i = 0; i<3 ; i++)
            {
                if(i==0)
                    next=head-1;
                else if(i==1)
                    next=head+1;
                else
                    next=head*2;
                if(next<0||next>maxn)    continue;
                if(!vis[next])
                {
                    q.push(next);  //压入
                    st[next]=st[head]+1;
                    vis[next]=true;
                }
                if(next==k)
                    return st[next];
            }
        }
    }
    int main()
    {
        int n , k ;
        while(cin>>n>>k){
            first();
            if(n>=k)
            {
                cout<<n-k<<endl;
                continue;
            }
            else
                cout<<bfs(n,k)<<endl;
        }
    }

       n-皇后问题,DFS解法:

       ACWING板子题地址

       题中已经说的很清楚了,什么叫n皇后。对于一个棋子的摆放,我们应该保证这个棋子所在位置的一列,斜方向和反斜方向没有棋子。怎么判断呢,我们引入bool类型的row[]数组,row[i]=true,表明这一列已经放过棋子了,false表示没有。这个row就解决了列问题,那么斜方向问题怎么解决呢?我们观察一下,题中规定的斜方向,都是符合y=x+b/y=-x+b方程的。b=y-x/b=x+y。同一个b,就是同一条斜线了。我的代码中规定了d[]表示斜方向,ud[]表示反斜方向。比如!d[u+i],表示x=u,y=i这条斜线上没有棋子,这个b=u+i之前没有出现过。前面就说过,由于斜率一样,所以只要保证这个b不一样,所在斜线就不一样。同理,反斜方向的也是一样,用b=y-x来判断,但是如果y-x<0的话,需要+n偏移一下,统一用ud[i-u+n]。

      if(!row[i]&&!d[u+i]&&!ud[i-u+n])表示,对于x=u,y=i这个点,只要同一列,两个斜线处均没有棋子,就符合要求,放上一枚棋子。

      其他的就是dfs的基本操作了,还原啦什么的...

      

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N = 27;
    char m[N][N];
    bool row[N],d[N],ud[N];
    int n;
    void first()
    {
        for(int i = 0 ; i< n ; i ++)
            for(int j = 0 ;  j < n ; j ++)
                m[i][j]='.';
        memset(row,false,sizeof(row));
        memset(d,false,sizeof(d));
        memset(ud,false,sizeof(ud));
    }
    void dfs(int u)
    {
        //cout<<u<<endl;
        if(u==n)
        {
            for(int i = 0 ; i < n ; i ++)
            {
    
                for(int j = 0 ; j < n ;j ++)
                    cout<<m[i][j];
                    cout<<endl;
            }
            cout<<endl;
            return ;
        }
        for(int i = 0 ; i < n ; i++)
        {
            if(!row[i]&&!d[u+i]&&!ud[i-u+n])
            {
                m[u][i]='Q';
                row[i]=d[u+i]=ud[i-u+n]=true;
                dfs(u+1);
                row[i]=d[u+i]=ud[i-u+n]=false;
                m[u][i]='.';
            }
        }
    }
    int main()
    {
    
        while(cin>>n)
        {
            first();
            dfs(0);
        }
    }

     另一种比较原始的搜索方式,比较慢:记录皇后数目,如果==n的话,就输出;

      

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N = 27;
    char m[N][N];
    bool row[N],d[N],ud[N],urow[N];
    int n;
    void dfs(int x,int y,int s)
    {
        //cout<<x<<"  "<<y<<"  "<<s<<endl;
        if(y==n)
        {
            x++;
            y=0;
        }
        if(x==n)
        {
            if(s==n)  //这行不能放入if(x==n)里面,因为不管数目达没达到,都要return 掉
            {
                for(int i=0;i<n;i++)
                puts(m[i]);
                puts("");
            }
            return ;
        }
        if(!row[x]&&!urow[y]&&!d[x+y]&&!ud[y-x+n])
        {
            m[x][y]='Q';
            row[x]=urow[y]=d[x+y]=ud[y-x+n]=true;
            dfs(x,y+1,s+1);
            m[x][y]='.';
            row[x]=urow[y]=d[x+y]=ud[y-x+n]=false;
        }
        dfs(x,y+1,s);
    }
    int main()
    {
        //int n;
        cin>>n;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                m[i][j]='.';
        dfs(0,0,0);
    }

     ACWING 844.走迷宫:https://www.acwing.com/problem/content/846/

      走迷宫,从左上角走到右下角,0可走,1不可走,问最少需要几步。

      BFS解法:  通过g[][]记录地图,d[][]初始化为-1用来保证一个点只能走一次以及记录每个点到达终点的距离。

      注意:使用以下语句来实现队列记录(x,y);

      

    #include<queue>
    typedef pair<int,int>pp;
    queue<int>q;
    q.push({1,2});
    pp t=q.front;
    那么:t.first=1,t.second=2

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    typedef pair<int,int>P; //!!!
    const int maxn = 105;
    int n,m;
    int g[maxn][maxn];
    int d[maxn][maxn];    //每个点到起点的距离 //没有走过 
    int dx[]={0,0,-1,1};
    int dy[]={1,-1,0,0};
    int bfs()
    {
        queue<P>q;
        memset(d,-1,sizeof(d));
        d[0][0]=0;
        q.push({0,0});
        while(!q.empty())
        {
            P t = q.front();
            q.pop();
            for(int i=0;i<4;i++)
            {
                int x=dx[i]+t.first;
                int y=dy[i]+t.second;
                if(x>=0&&y>=0&&x<n&&y<m&&g[x][y]==0&&d[x][y]==-1)
                {
                    d[x][y]=d[t.first][t.second]+1;
                    q.push({x,y});
                }
            }
        }
        return d[n-1][m-1];
    }
    int main()
    {
        cin>>n>>m;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                cin>>g[i][j];
        cout<<bfs()<<endl;
        return 0;
    }

    跟这个题基本一模一样的:POJ3984:http://poj.org/status

    不同的是这个是要输出路径。我的做法是,pair一个ing[x][y],ing[x][y].first,ing[x][y].second记录x,y的前一个点。因为是逆序,所以又存进一个结构体里,再逆序输出,才变成正序了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    typedef pair<int,int>P; //!!!
    const int maxn = 105;
    P ing[maxn][maxn];
    int n,m;
    int g[maxn][maxn];
    int d[maxn][maxn];    //每个点到起点的距离 //没有走过 
    int dx[]={0,0,-1,1};
    int dy[]={1,-1,0,0};
    struct node
    {
        int x,y;
    }st[maxn];
    void bfs()
    {
        queue<P>q;
        memset(d,-1,sizeof(d));
        d[0][0]=0;
        q.push({0,0});
        while(!q.empty())
        {
            P t = q.front();
            q.pop();
            for(int i=0;i<4;i++)
            {
                int x=dx[i]+t.first;
                int y=dy[i]+t.second;
                if(x>=0&&y>=0&&x<5&&y<5&&g[x][y]==0&&d[x][y]==-1)
                {
                    d[x][y]=d[t.first][t.second]+1;
                    ing[x][y].first=t.first;
                    ing[x][y].second=t.second;
                    q.push({x,y});
                }
            }
        }
        return ;
    }
    int main()
    {
        //cin>>n>>m;
        for(int i=0;i<5;i++)
            for(int j=0;j<5;j++)
                cin>>g[i][j];
        bfs();
        int x=4,y=4;
        int tot=0;
        while(!(x==0&&y==0))
        {
            st[tot].x=x;
            st[tot].y=y;
            tot++;
            int tx=x,ty=y;
            x=ing[tx][ty].first;
            y=ing[tx][ty].second;
        }
        cout<<"(0, 0)"<<endl;
        for(int i=tot-1;i>=0;i--)
            printf("(%d, %d)
    ",st[i].x,st[i].y);
        return 0;
    }

     经典油田问题:POJ  2386  http://poj.org/problem?id=2386

    DFS,碰到W,就变成‘.’,再看八个方向,如果有W,就DFS。最后DFS的次数就是答案。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn = 200;
    char s[maxn][maxn];
    int n,m;
    void dfs(int x,int y)
    {
        if(x<0||y<0||x>n||y>m)
            return ;
        s[x][y]='.';
        for(int i=-1;i<=1;i++)
        {
            for(int j=-1;j<=1;j++)
            {
                int xx=x+i;
                int yy=y+j;
                if(xx>=0&&yy>=0&&xx<n&&yy<m&&s[xx][yy]=='W')
                {
                    dfs(xx,yy);
                }
            }
        }
        
    }
    int main()
    {
        cin>>n>>m;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                cin>>s[i][j];
        int ans=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
            {
                if(s[i][j]=='W')
                {
                    dfs(i,j);
                    ans++;
                }
            }
        cout<<ans<<endl;
    }
  • 相关阅读:
    移动 App 接入 QQ 登录/分享 图文教程
    Word 最后一页无法删除-解决办法
    Java快速入门-04-Java.util包简单总结
    Java快速入门-03-小知识汇总篇(全)
    SSM 框架-06-详细整合教程(IDEA版)(Spring+SpringMVC+MyBatis)
    二叉树的镜像
    浅析I/O模型及其设计模式
    远程方法调用(RMI)原理与示例
    树的子结构
    合并两个排序的链表
  • 原文地址:https://www.cnblogs.com/liyexin/p/12238377.html
Copyright © 2020-2023  润新知