BFS 题目 总结

首先介绍 一下BFS 和 DFS 之间的区别 

首先 上图

 

         这个图 如果 用 DFS 搜索的应该是 从 根节点 1 开始 然后沿着 从左向右 将 每个分支 搜索到底 比如 搜索到 5这个节点时

 就是 5-->9 然后回去 再 5-->10 -->14再回去 10-->15 再回去 将每个分支搜索完毕 

         用 BFS的话 也是 从 更节点开始搜索但是 BFS 要 通过  一个叫队列 的 东西

        队列 是一个先进先出的类似于数组的数据结构 但是是很简单 的    

        queue<数据类型>变量名    这就是一个简单的定义   

      BFS的搜索顺序 是将 靠近这个节点且距离相等的点 搜索完毕  这里需要标记一下 该节点是否在队列里面 这个图的搜索顺序是从1开始 然后依次到达 15;

      接下来是几个例题 关于BFS的 

     第一个   PO 2251  点这里  http://poj.org/problem?id=2251

     这是一个 有六条路径的类似于迷宫的BFS

Source Code

Problem: 2251		User: rg180120
Memory: 856K		Time: 47MS
Language: G++		Result: Accepted
Source Code
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;

struct Node
{
    int x,y,z;
    int len;
};

Node c,d;

char a[35][35][35];
int b[35][35][35];
int L,R,C;

int f[3][6]={{1,-1,0,0,0,0},
            {0,0,1,-1,0,0},
            {0,0,0,0,1,-1}};

int s2[35][35][35];
int flag;
int si,sj,sk;

bool pop(int x,int y,int z)
{
    return (x>=1&&x<=L&&y>=1&&y<=R&&z>=1&&z<=C);
}

int bfs(int si,int sj,int sk)
{
    queue<Node>s;
    c.x=si;
    c.y=sj;
    c.z=sk;
    c.len=0;
    s.push(c);
    while(!s.empty())
    {
        d=s.front();
        s.pop();
        c.len=d.len+1;
        for(int i=0;i<6;i++)
        {
            c.x=d.x+f[0][i];
            c.y=d.y+f[1][i];
            c.z=d.z+f[2][i];
            if(pop(c.x,c.y,c.z)&&!b[c.x][c.y][c.z]&&a[c.x][c.y][c.z]!='#')
            {
                if(a[c.x][c.y][c.z]=='E')
                    return c.len;
                b[c.x][c.y][c.z]=1;
                s.push(c);
            }
        }
    }
    return -1;
}


int main()
{
    while(cin>>L>>R>>C)
    {
        if(!L&&!R&&!C)  break;
        memset(b,0,sizeof(b));
        for(int i=1;i<=L;i++)
        {
            for(int j=1;j<=R;j++)
            {
                for(int k=1;k<=C;k++)
                {
                    cin>>a[i][j][k];
                    if (a[i][j][k]=='S')
                    {
                        si=i;
                        sj=j;
                        sk=k;
                    }
                }
            }
        }
        flag=bfs(si,sj,sk);
        if (flag==-1)
            cout << "Trapped!" << endl;
        else
             cout << "Escaped in " << flag << " minute(s)." << endl;

    }
    return 0;
}

          下一道    点这里 POJ3278    http://poj.org/problem?id=3278

          这道题目的意思是 从N 点到K点   可以 通过向前一步 即为在这个数轴上加一 还有向后一步 即为减一 
还有一个是向前走到2倍的位置如 从4到8  ,这三种方式每进行一步耗时都为一秒, 怎么通过这三种方式到达K点最快 

Source Code

Problem: 3278		User: rg180120
Memory: 1512K		Time: 32MS
Language: G++		Result: Accepted
Source Code
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;

const int maxn=100000;

typedef long long ll;


int n,k;
int ans;
int vis[maxn+7];
int dis[maxn+7];
queue<int>s;

int bfs(int n)
{
    int head,next;
    s.push(n);
    dis[n]=0;
    vis[n]=1;
    while(!s.empty())
    {
        head=s.front();
        s.pop();
        for(int i=1;i<=3;i++)
        {
            if(i==1)
                next=head+1;
           else if(i==2)
                next=head-1;
           else if(i==3)
                next=head*2;
            if(next<0 || next>maxn) continue; //排除出界情况
            if(!vis[next])
            {
                vis[next]=1;
                dis[next]=dis[head]+1;
            
                s.push(next);
            }
        
            if(next==k)
                return dis[next];
        }
    }
    return -1;
}

int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        memset(vis,0,sizeof(vis));
        memset(dis,0,sizeof(dis));
        while(!s.empty()) s.pop();
        ans=bfs(n);
        cout<<ans<<endl;
    }
}

再来一道 POJ 1426 http://poj.org/problem?id=1426

 

这道题目 是非常有意思的题目  意思大体是说 给你一个数 找到 这个数的一个倍数光有1和0组成 答案有多个 每个数输出一个 就行  这道题 一上来看起来和BFS没大有关系 然后你仔细 想  是不是 相当于 从1开始的有两条路一个是*10一个数是*10+1;那么这样

就是一个典型的BFS题目的 代码是非常简单的

Source Code

Problem: 1426		User: rg180120
Memory: 5000K		Time: 438MS
Language: G++		Result: Accepted
Source Code
#include<cstdio>
#include<iostream>
#include <algorithm>
#include<queue>
using namespace std;

typedef long long ll;

queue<ll>s;
ll d;
ll temp1,temp2;
int n;

void bfs()
{
    s.push(1);
    while(!s.empty())
    {
        d=s.front();
        s.pop();
        if(d%n==0)
        {
            cout<<d<<endl;
            return ;
        }
        else
        {
            temp1=d*10;
            temp2=d*10+1;
            s.push(temp1);
            s.push(temp2);
        }
    }
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)    break;
        bfs();
        while(!s.empty())   s.pop();

    }
    return 0;
}

还有一个 POJ 3126 http://poj.org/problem?id=3126

 

          这道题目 是说 给你一个T;表示有T组输入 然后 每组两个4位数的素数的数据 N,,M; 意思是 将N变成M每次 只能改变一位数且每次改变位到应该是素数然后从N最短需要几步到M  首先对这个题目需要先打表 主要将 1000到10000的素数标记出来 

然后分别对每位数据进行 操作 

Source Code

Problem: 3126		User: rg180120
Memory: 764K		Time: 16MS
Language: G++		Result: Accepted
Source Code
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;

typedef long long ll;
const int maxn=10030;


struct Node
{
    int date;
    int len;
};


int t,n,m;
int vis[maxn+7];
int isprime[maxn+7];


void prime()
{
    memset(isprime,0,sizeof(isprime));
    for(int i=2;i<=maxn;i++)
    {
        if(!isprime[i])
        for(int j=i*2;j<=maxn;j+=i)
            isprime[j]=1;
    }
}


Node w,l;
queue<Node>q;


void bfs(int n,int m)
{

    vis[n]=1;
    l.date=n;
    l.len=0;
    q.push(l);
    while(!q.empty())
    {
        l=q.front();
        q.pop();
       // cout<<l.date<<endl;
        if(l.date==m)
        {
            cout<<l.len<<endl;
            return ;
        }
        for(int i=1;i<=9;i++)  //个
        {
            int s=l.date/10*10+i;
            if(!vis[s]&&!isprime[s])
            {
                vis[s]=1;
                w.date=s;
                w.len=l.len+1;
                q.push(w);
            }

        }
        for(int i=0;i<=9;i++)   //十
        {
            int s=l.date/100*100+l.date%10+i*10;
            if(!vis[s]&&!isprime[s])
            {
                vis[s]=1;
                w.date=s;
                w.len=l.len+1;
                q.push(w);
            }
        }
        for(int i=0;i<=9;i++)   //百
        {
            int s=l.date/1000*1000+l.date%100+i*100;
            if(!vis[s]&&!isprime[s])
            {
                vis[s]=1;
                w.date=s;
                w.len=l.len+1;
                q.push(w);
            }
        }
        for(int i=1;i<=9;i++) //千
        {
            int s=l.date%1000+i*1000;
            if(!vis[s]&&!isprime[s])
            {
                vis[s]=1;
                w.date=s;
                w.len=l.len+1;
                q.push(w);
            }
        }
    }
   // cout<<"Impossible"<<endl;
}


int main()
{
    cin>>t;
    prime();
    while(t--)
    {
        cin>>n>>m;
        while(!q.empty())   q.pop();
        memset(vis,0,sizeof(vis));
        bfs(n,m);
    }
    return 0;
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值