基礎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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章