zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    创建类以及引用一个类
    修改hosts文件
    微信第三方登录接口开发
    Android定位
    Leetcode 102. Binary Tree Level Order Traversal
    Leetcode 725. Split Linked List in Parts
    Leetcode 445. Add Two Numbers II
    Leetcode 328. Odd Even Linked List
    Leetcode 237. Delete Node in a Linked List
    Leetcode 234. Palindrome Linked List
  • 原文地址:https://www.cnblogs.com/liyexin/p/12238377.html
Copyright © 2011-2022 走看看