基础BFS(poj 3278, poj1426, poj 3126, poj 3414, hdoj 1495, hdoj 1312)

小白要跟kuangbin大佬刷题嗷~~
下面是用到BFS的题,持续更新?
poj 3278 catch that cow
思路较简单,纯板子题 ,直接上代码

#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
int dir[2]={-1,1};
int vis[100003];//标记是否之前访问过
int n,k;
struct node
{
    int pos;
    int step;
};
bool check(int pos)
{
    if(pos<0||pos>100003)
        return false;
    else
        if(vis[pos]==1)
        return false;
    return true;
}
int bfs()
{
    node start,next;
    queue<node>q;
    start.pos=n;
    start.step=0;
    q.push(start);
    while(!q.empty())
    {
        node tmp=q.front();
        q.pop();
        if(tmp.pos==k)
            return tmp.step;
        for(int i=0;i<3;i++)
        {
            next=tmp;
            if(i!=2)
                next.pos+=dir[i];
            else
                next.pos*=2;
            if(check(next.pos))
            {
                next.step++;
                vis[next.pos]=1;
                q.push(next);
            }
        }
    }
}
int main()
{
    cin>>n>>k;
    memset(vis,0,sizeof(vis));
    int ans=bfs();
    cout<<ans<<endl;
}

poj 1426 Find The Multiple
读题真的很重要啊,不不不,是英语真的很重要啊!!!
题意是说找一个只由0,1组成的十进制数能够把n除尽,答案有很多,写出一个就可以。题中给出m的位数不大于100,然而我用 long long 试了试也是可以的emm
用bfs搜就可以,不过每次不符合要求的时候要在队列中push两个数,一个是tmp乘以10,另一个是tmp乘以10+1

#include <iostream>
#include <queue>
using namespace std;
typedef long long int ll;
void bfs(int n)
{
    queue<ll>q;
    q.push(1);
    while(!q.empty())
    {
        ll tmp=q.front();
        q.pop();
        if(tmp%n==0)
        {
            cout<<tmp<<endl;
            return;
        }
        q.push(tmp*10);
        q.push(tmp*10+1);
    }
}
int main()
{
    int n;
    while(cin>>n&&n)
    {
        bfs(n);
    }
}

poj 3126 Prime Path
题目大意:将一个素数变成另一个素数最少需要多少步,其中每次只能改变四位数中的一个数,并且得到的每一个数都必须是素数。
这道题问到“最少多少步”,因此选择BFS来解。首先用埃氏筛将素数筛出来
埃氏筛:要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。)
然后依次改变四位数中的每一位,通过队列来实现BFS

#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
int a,b;
int isprime[10002];
int vis[10000];
struct node
{
    int num;
    int step;
};
int bfs()
{
    queue<node>q;
    node start;
    start.num=a;
    start.step=0;
    q.push(start);
    while(!q.empty())
    {
        node tmp=q.front();
        q.pop();
        if(tmp.num==b)
            return tmp.step;
        vis[tmp.num]=1;
        for(int i=0;i<=9;i++)//个位
        {
            node next=tmp;
            int p=tmp.num/10*10+i;
            if(!isprime[p]&&!vis[p])
            {
                next.num=p;
                next.step++;
                q.push(next);
            }
        }
        for(int i=0;i<=9;i++)//十位
        {
            node next=tmp;
            int p=tmp.num%10+tmp.num/100*100+i*10;
            if(!isprime[p]&&!vis[p])
            {
                next.num=p;
                next.step++;
                q.push(next);
            }
        }
        for(int i=0;i<=9;i++)//百位
        {
            node next=tmp;
            int p=tmp.num%100+tmp.num/1000*1000+i*100;
            if(!isprime[p]&&!vis[p])
            {
                next.num=p;
                next.step++;
                q.push(next);
            }
        }
        for(int i=1;i<=9;i++)//千位
        {
            node next=tmp;
            int p=tmp.num%1000+i*1000;
            if(!isprime[p]&&!vis[p])
            {
                next.num=p;
                next.step++;
                q.push(next);
            }
        }
    }
    return -1;
}
int main()
{
    memset(isprime,0,sizeof(isprime));
    for(int i=2;i*i<10002;i++)
    {
        if(!isprime[i])
        {
            for(int j=2*i;j<10002;j+=i)
                isprime[j]=1;
        }
    }
    int n;
    cin>>n;
    while(n--)
    {
        memset(vis,0,sizeof(vis));
        cin>>a>>b;
        if(a==b)
            cout<<0<<endl;
        else
        {
            int ans=bfs();
            if(ans==-1)
                cout<<"Impossible"<<endl;
            else
                cout<<ans<<endl;
        }
    }
}

poj 3414 Pots
此题是阿伟自己写出来的hhhhh~~~(咳咳,表示下开心)
题目大意:给你两个容器,然后对这两个容器有三种操作:
1.FILL(i) 将第i个容器装满(i=1,2)
2.DROP(i) 将第i个容器里的水倒光
3.POUR(i,j) 将i中的水倒入j中,会有两种结果,i容器变空,或者j容器装满
题目给出两个容器的容量以及目标水量(两个容器中任意一个到达目标水量都算完成任务),计算出最少的操作数,使得达到目标水量,并把流程写出来,如果达不到,则输出impossible
题解:本题是说最少的操作数,所以我用的BFS,然而需要将操作流程也要记录下来,这个就比较麻烦,由于操作流程总共只有6种,因此可以用1-6来分别代表操作数,将操作流程以字符串的形式存在结构体中,最后对字符串挨个读取,对应相应的操作就可以了。
这道题的循环还有check都比较麻烦,我用了switch分情况,还有就是BFS核心内容一定不能忘,尤其是先后顺序。
贴上AC代码,嘿嘿嘿~

#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
int a,b,c;
int vis[101][101];
struct node
{
    int one;
    int two;
    string step;
};
bool check(int t,node tmp,node next)
{
    switch (t)
    {
    case 1:
        if(tmp.one>=a||vis[next.one][next.two])
            return false;
        break;
    case 2:
        if(tmp.two>=b||vis[next.one][next.two])
            return false;
        break;
    case 3:
        if(tmp.one<=0||vis[next.one][next.two])
            return false;
        break;
    case 4:
        if(tmp.two<=0||vis[next.one][next.two])
            return false;
        break;
    case 5:
        if(tmp.one<=0||tmp.two>=b||vis[next.one][next.two])
            return false;
        break;
    case 6:
        if(tmp.two<=0||tmp.one>=a||vis[next.one][next.two])
            return false;
        break;
    }
    return true;
}
string bfs()
{
    queue<node>q;
    node start,next;
    start.one=0;
    start.two=0;
    start.step="";
    vis[0][0]=1;
    q.push(start);
    while(!q.empty())
    {
        node tmp=q.front();
        q.pop();
        if(tmp.one==c||tmp.two==c)
            return tmp.step;
        for(int i=1;i<=6;i++)
        {
            next=tmp;
            switch (i)
            {
            case 1:
                next.one=a;
                if(check(i,tmp,next))
                {
                    next.step+='1';
                    q.push(next);
                    vis[next.one][next.two]=1;
                }
                break;
            case 2:
                next.two=b;
                if(check(i,tmp,next))
                {
                    next.step+='2';
                    q.push(next);
                    vis[next.one][next.two]=1;
                }
                break;
            case 3:
                next.one=0;
                if(check(i,tmp,next))
                {
                    next.step+='3';
                    q.push(next);
                    vis[next.one][next.two]=1;
                }
                break;
            case 4:
                next.two=0;
                if(check(i,tmp,next))
                {
                    next.step+='4';
                    q.push(next);
                    vis[next.one][next.two]=1;
                }
                break;
            case 5:
                if(next.one+next.two>b)
                {
                    next.one=next.one+next.two-b;
                    next.two=b;
                }
                else
                {
                    next.two+=next.one;
                    next.one=0;
                }
                if(check(i,tmp,next))
                {
                    next.step+='5';
                    q.push(next);
                    vis[next.one][next.two]=1;
                }
                break;
            case 6:
                if(next.one+next.two>a)
                {
                    next.two=next.one+next.two-a;
                    next.one=a;
                }
                else
                {
                    next.one+=next.two;
                    next.two=0;
                }
                if(check(i,tmp,next))
                {
                    next.step+='6';
                    q.push(next);
                    vis[next.one][next.two]=1;
                }
                break;
            }
        }
    }
    return "-1";
}
int main()
{
    memset(vis,0,sizeof(vis));
    cin>>a>>b>>c;
    string ans=bfs();
    if(ans=="-1")
        cout<<"impossible"<<endl;
    else
    {
        int len=ans.length();
        cout<<len<<endl;
        for(int i=0;i<len;i++)
        {
            switch (ans[i]-'0')
            {
            case 1:
                cout<<"FILL(1)"<<endl;
                break;
            case 2:
                cout<<"FILL(2)"<<endl;
                break;
            case 3:
                cout<<"DROP(1)"<<endl;
                break;
            case 4:
                cout<<"DROP(2)"<<endl;
                break;
            case 5:
                cout<<"POUR(1,2)"<<endl;
                break;
            case 6:
                cout<<"POUR(2,1)"<<endl;
                break;
            }
        }
    }
}

hdoj 1495 非常可乐
此题和上一题差不多,都是倒水问题,刚开始怎么都读不懂题 (可能是我语文不太好),看了大佬的题解之后才了解题意。。

题目大意: 有一瓶可乐和两个给定容量的杯子(没有刻度),问如何倒水才能让三个容器中的两个平分这瓶可乐,如果可以写出操作次数,不可以输出“NO”

题解: 刚开始不怎么理解“没有刻度”,还以为倒水的人很牛逼,知道到多少算是可以了。。后来才知道,如果没有刻度的话,只能将一个杯子倒满,或者将另一个杯子倒空,只有这样才能知道所倒水的具体容积,这个操作和上一题的“POUR(i,j) ”操作是一样的,本题枚举6种倒法,然后挨个检查,具体思路和上一题差不多,还要注意一点,当可乐的体积是奇数的时候,肯定不能平分,在这个地方可以剪枝。

上代码!

#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
int s,n,m;
int vis[101][101][101];
struct node
{
    int s;
    int n;
    int m;
    int step;
};
bool check(int t,node tmp,node next)
{
    switch (t)
    {
    case 1:
        if(tmp.s<=0||tmp.n>=n||vis[next.s][next.n][next.m])
            return false;
        break;
    case 2:
        if(tmp.s<=0||tmp.m>=m||vis[next.s][next.n][next.m])
            return false;
        break;
    case 3:
        if(tmp.n<=0||tmp.s>=s||vis[next.s][next.n][next.m])
            return false;
        break;
    case 4:
        if(tmp.n<=0||tmp.m>=m||vis[next.s][next.n][next.m])
            return false;
        break;
    case 5:
        if(tmp.m<=0||tmp.s>=s||vis[next.s][next.n][next.m])
            return false;
        break;
    case 6:
        if(tmp.m<=0||tmp.n>=n||vis[next.s][next.n][next.m])
            return false;
        break;
    }
    return true;
}
int bfs()
{
    node start,next;
    start.s=s;
    start.n=0;
    start.m=0;
    start.step=0;
    vis[s][0][0]=1;
    queue<node>q;
    q.push(start);
    while(!q.empty())
    {
        node tmp=q.front();
        q.pop();
        if((tmp.s==0&&(tmp.m==tmp.n))||(tmp.m==0&&tmp.s==tmp.n)||(tmp.n==0&&tmp.s==tmp.m))
            return tmp.step;
        for(int i=1;i<=6;i++)
        {
            next=tmp;
            switch (i)
            {
            case 1://s->n
                if(next.s+next.n>n)
                {
                    next.s=next.s+next.n-n;
                    next.n=n;
                }
                else
                {
                    next.n+=next.s;
                    next.s=0;
                }
                break;
            case 2://s->m
                if(next.s+next.m>m)
                {
                    next.s=next.s+next.m-m;
                    next.m=m;
                }
                else
                {
                    next.m+=next.s;
                    next.s=0;
                }
                break;
            case 3://n->s
                if(next.s+next.n>s)
                {
                    next.n=next.s+next.n-s;
                    next.s=s;
                }
                else
                {
                    next.s+=next.n;
                    next.n=0;
                }
                break;
            case 4://n->m
                if(next.n+next.m>m)
                {
                    next.n=next.n+next.m-m;
                    next.m=m;
                }
                else
                {
                    next.m+=next.n;
                    next.n=0;
                }
                break;
            case 5://m->s
                if(next.s+next.m>s)
                {
                    next.m=next.s+next.m-s;
                    next.s=s;
                }
                else
                {
                    next.s+=next.m;
                    next.m=0;
                }
                break;
            case 6://m->n
                if(next.m+next.n>n)
                {
                    next.m=next.m+next.n-n;
                    next.n=n;
                }
                else
                {
                    next.n+=next.m;
                    next.m=0;
                }
                break;
            }
            if(check(i,tmp,next))
            {
                vis[next.s][next.n][next.m]=1;
                next.step++;
                q.push(next);
            }
        }
    }
    return -1;
}
int main()
{
    while(cin>>s>>n>>m&&s)
    {
        if(s&1)
        {
            cout<<"NO"<<endl;
            continue;
        }
        memset(vis,0,sizeof(vis));
        int ans=bfs();
        if(ans==-1)
            cout<<"NO"<<endl;
        else
            cout<<ans<<endl;
    }
}

hdoj1312 Red and Black
记录下今天的日期:8.30 (最近有些懒散,之前学的东西感觉快忘了emm,赶紧做几道题回忆一下)

题目大意: 有一个矩形瓷砖地,由红黑两种颜色的瓷砖构成,给出一个人的位置,这个人只能走黑色瓷砖,红色瓷砖可以看做是墙,不能过去。问从这个人的位置出发,最多能走多少块瓷砖。(最终结果包括他自己!)

题解: 这应该算是BFS的水题了emm,但是我做的时候还是花费了不少的时间,得赶紧将暑假学的东西拾起来,不然就白学了(手动捂脸)。这题需要注意的一点就是最终结果是包括自己的,也就是说,如果这个人的四周全是红瓷砖(墙),那如果不加特判的话,结果就会是0,而正确结果应该是1,因此在最后要加上特判。

(这题应该也可以用DFS做,如果做出来的话会写在我的另一篇博客里)

AC代码:

#include <iostream>
#include <iomanip>
#include <queue>
#include <string.h>
using namespace std;
char maps[21][21];
int vis[21][21];
int xx,yy,w,h,ans=0;
int dir[4][2]=
{
    {0,1},
    {0,-1},
    {1,0},
    {-1,0},
};
struct node
{
    int x;
    int y;
};
bool check(int x,int y)
{
    if(x<0||y<0||x>=h||y>=w||vis[x][y])
        return false;
    if(maps[x][y]=='#')
        return false;
    return true;
}
void bfs()
{
    queue<node>q;
    node start,next;
    start.x=xx;
    start.y=yy;
    q.push(start);
    while(!q.empty())
    {
        node tmp=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            next=tmp;
            next.x+=dir[i][0];
            next.y+=dir[i][1];
            if(check(next.x,next.y))
            {
                ans++;
                q.push(next);
                vis[next.x][next.y]=1;
            }
        }
    }
}
int main()
{
    while(cin>>w>>h&&w+h)
    {
        ans=0;
        memset(maps,0,sizeof(maps));
        memset(vis,0,sizeof(vis));
        for(int i=0;i<h;i++)
        {
            for(int j=0;j<w;j++)
            {
                cin>>maps[i][j];
                if(maps[i][j]=='@')
                {
                    xx=i;
                    yy=j;
                }
            }
        }
        bfs();
        if(!ans)//特判,判断是否这个人周围全是红瓷砖
            ans=1;
        cout<<ans<<endl;
    }
}
发布了32 篇原创文章 · 获赞 12 · 访问量 1394

猜你喜欢

转载自blog.csdn.net/qq_18873031/article/details/98509242