数学建模简单bfs跳棋

题目一:

总共七个格子,最左边有三颗棋子。用跳棋的规则,最少的步骤使得三个棋子走到七个格子的最右边。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;

int a[8];    //保存信息,比如112保存为1110000
int visi[1002];   //看某个状态有没有被访问
int next[1002];   //记录所存的状态信息
int res[1002];

int con(int t1,int t2,int t3)
{
    int ans=0;
    ans+=pow(2,7-t1);
    ans+=pow(2,7-t2);
    ans+=pow(2,7-t3);
    return ans;
}

void bfs(int sta)
{
    queue<int> mq;
    mq.push(sta);
    int cur,i;
    int t1,t2,t3;

    while(!mq.empty())
    {
        cur=mq.front();
        int pc=cur;
        mq.pop();
        if(cur==7)   //终状态为0000111
        {
            break;
        }
        for(i=7;i>=1;i--)   //再解压状态信息
        {
            a[i]=cur%2;
            cur=cur/2;
        }
        cur=pc;

        //先找到三个球的位置
        for(i=1;i<=7;i++)
        {
            if(a[i])
            {
                t1=i;
                i++;
                break;
            }
        }
        for(;i<=7;i++)
        {
            if(a[i])
            {
                t2=i;
                i++;
                break;
            }
        }
        for(;i<=7;i++)
        {
            if(a[i])
            {
                t3=i;
                i++;
                break;
            }
        }

        //cout<<t1<<" "<<t2<<" "<<t3<<endl;

        //现在就是最麻烦的枚举状态的时候了
        //我们假使三种情况,动t1,t2,t3如果能动的话,每次都动最远
        int tmp;
        //先动第一个
        if(t2>t1+1)   //中间有空格
        {
            tmp=con(t1+1,t2,t3);
            if(!visi[tmp])   //如果此状态没访问过
            {
                visi[tmp]=1;
                next[tmp]=cur; //记录状态转移过程
                mq.push(tmp);  //把状态加入队列中
            }
        }
        else if((t2==t1+1&&t3>t2+2)||(t2==t1+1&&t3==t2+2&&t3==7))
        {
            tmp=con(t2,t2+1,t3);
            if(!visi[tmp])   //如果此状态没访问过
            {
                visi[tmp]=1;
                next[tmp]=cur; //记录状态转移过程
                mq.push(tmp);  //把状态加入队列中
            }
        }
        else if(t2==t1+1&&t3==t2+2&&t3<7)
        {
            tmp=con(t2,t3,t3+1);
            if(!visi[tmp])   //如果此状态没访问过
            {
                visi[tmp]=1;
                next[tmp]=cur; //记录状态转移过程
                mq.push(tmp);  //把状态加入队列中
            }
        }
        else if(t2==t1+1&&t3==t2+1)
        {
            //动不了第一个棋
        }

        //再试着动第二个
        if(t3>t2+1)  //t2后面有空格
        {
            tmp=con(t1,t2+1,t3);
            if(!visi[tmp])   //如果此状态没访问过
            {
                visi[tmp]=1;
                next[tmp]=cur; //记录状态转移过程
                mq.push(tmp);  //把状态加入队列中
            }
        }
        else if(t3==t2+1&&t3==7)
        {
            //动不了第二个棋
        }
        else if(t3==t2+1&&t3<7)
        {
            tmp=con(t1,t3,t3+1);
            if(!visi[tmp])   //如果此状态没访问过
            {
                visi[tmp]=1;
                next[tmp]=cur; //记录状态转移过程
                mq.push(tmp);  //把状态加入队列中
            }
        }

        //再试着动第三个
        if(t3<7)
        {
            tmp=con(t1,t2,t3+1);
            if(!visi[tmp])   //如果此状态没访问过
            {
                visi[tmp]=1;
                next[tmp]=cur; //记录状态转移过程
                mq.push(tmp);  //把状态加入队列中
            }
        }
        else if(t3==7)
        {
            //动不了第三个棋
        }

        //break;
    }
}

int main()
{
    int i,sta=0,j;
    for(i=1;i<=3;i++)
    {
        a[i]=1;
        sta+=pow(2,7-i);
    }
    for(i=4;i<=7;i++)
    {
        a[i]=0;
    }

    //cout<<sta<<endl;
    //初始状态为1110000  初始值为112
    memset(visi,0,sizeof(visi));    //把visi数组全部置为0都没访问过
    bfs(sta);
    int tt=0,tmp;
    tmp=7;
    while(tmp!=112)
    {
        res[tt++]=tmp;
        //cout<<tmp<<endl;
        tmp=next[tmp];
    }
    res[tt++]=tmp;

    /*for(i=tt-1;i>=0;i--)
        cout<<res[i]<<" ";
    cout<<endl;*/
    /*cout<<next[7]<<endl;
    cout<<next[11]<<endl;
    cout<<next[26]<<endl;
    cout<<next[28]<<endl;
    cout<<next[44]<<endl;
    cout<<next[104]<<endl;*/

    for(i=tt-1;i>=0;i--)
    {
        int qq=res[i];
        for(j=7;j>=1;j--)
        {
            a[j]=qq%2;
            qq=qq/2;
        }

        for(j=1;j<=7;j++)
            cout<<a[j];
        cout<<endl;
    }
    return 0;
}

运行结果:


题目二:

总共七个格子,最左边有三颗白棋,最右边有三颗黑棋。用跳棋的规则,最少的步骤使得三个白棋走到最右边,三个黑棋走到最左边。

还有一个规则,自己只能通过自己的棋子作为炮台跳。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<cstdlib>
using namespace std;

int a[8];    //保存信息,比如112保存为1110000
int b[8];
int visi[2500];   //看某个状态有没有被访问
int next[2500];   //记录所存的状态信息
int res[2500];

void output()
{
    for(int i=1;i<=7;i++)
        cout<<a[i]<<" ";
    cout<<endl;
}

int con()
{
    int i;
    int ans=0;
    for(i=1; i<=7; i++)
        ans+=b[i]*pow(3,7-i);
    return ans;
}

void mcpy()
{
    int i;
    for(i=1; i<=7; i++)
        b[i]=a[i];
}

void bfs(int sta)
{
    int mq[2500];
    int ps=0,pen=1;
    //pstart  pend
    mq[ps]=sta;
    int cur,i;
    int t;

    while(ps<pen)   //队列中还有值
    {
        cur=mq[ps];
        int pc=cur;
        ps++;

        if(cur==2119)   //终状态为2220111
        {
            //cout<<"dsdsd"<<endl;
            break;
        }

        for(i=7; i>=1; i--) //再解压状态信息
        {
            a[i]=cur%3;
            cur=cur/3;
        }
        cur=pc;

        for(i=1; i<=7; i++)
        {
            if(a[i]==0)
            {
                t=i;     //记录空格的位置
                break;
            }
        }

        if(t+1<=7&&a[t+1]==2)   //黑棋左移1
        {
            mcpy();
            b[t]=2,b[t+1]=0;
            int tmp=con();
            if(!visi[tmp])
            {
                visi[tmp]=1;
                next[tmp]=cur;
                mq[pen++]=tmp;
            }
        }
        else if(t+2<=7&&a[t+1]==1&&a[t+2]==2)   //黑棋左移2
        {
            mcpy();
            b[t]=2,b[t+2]=0;
            int tmp=con();
            if(!visi[tmp])
            {
                visi[tmp]=1;
                next[tmp]=cur;
                mq[pen++]=tmp;
            }
        }
        if(t-1>=1&&a[t-1]==1)   //白棋右移1
        {
            mcpy();
            b[t]=1,b[t-1]=0;
            int tmp=con();
            if(!visi[tmp])
            {
                visi[tmp]=1;
                next[tmp]=cur;
                mq[pen++]=tmp;
            }
        }
        else if(t-2>=1&&a[t-1]==2&&a[t-2]==1)   //白棋右移2
        {
            mcpy();
            b[t]=1,b[t-2]=0;
            int tmp=con();
            if(!visi[tmp])
            {
                visi[tmp]=1;
                next[tmp]=cur;
                mq[pen++]=tmp;
            }
        }
    }
}

int main()
{
    int i,sta=0,j;
    for(i=1; i<=3; i++)
    {
        a[i]=1;
        sta+=a[i]*pow(3,7-i);
    }
    for(i=4; i<=4; i++)
    {
        a[i]=0;
    }
    for(i=5; i<=7; i++)
    {
        a[i]=2;
        sta+=a[i]*pow(3,7-i);
    }

    //cout<<sta<<endl;
    //初始状态为1110222  初始值为1079
    memset(visi,0,sizeof(visi));    //把visi数组全部置为0都没访问过
    cout<<sta<<endl;
    bfs(sta);

    int tt=0,tmp;
    tmp=2119;
    while(tmp!=1079)
    {
        res[tt++]=tmp;
        tmp=next[tmp];
    }
    res[tt++]=tmp;

    cout<<"总共需要:  "<<tt-1<<"步."<<endl;
    for(i=tt-1;i>=0;i--)
    {
        int qq=res[i];
        for(j=7;j>=1;j--)
        {
            a[j]=qq%3;
            qq=qq/3;
        }

        for(j=1;j<=7;j++)
            cout<<a[j];
        cout<<endl;
    }
    return 0;
}

运行结果:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值