传教士与野人过河问题(二)

关于上一篇的传教士与野人过河问题,递归固然精妙,但是只能输出一个解,如果想递归还要输出所有解,限于水平我确实想不出什么好办法。

作为人工智能课程的作业,我写了一个非递归的方法,目前只对几种情况做了检验可以输出所有解。

作为菜鸟,开始的时候在网上搜索确实好些理论都看不懂,所以在此把我的思路写在这里,不见得无暇,只为抛砖引玉


定义部分:

#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#define MAXSIZE 30

using namespace std;

typedef struct{
int person;                      //左岸传教士人数
int wild;                        //左岸野人人数
bool boat;                       //true表示船在左岸
int method;                      //到达本状态上一步使用的方法
int Last;                        //记录父状态
}state;

int LastMethod=0;                //记录上一步使用的方法,防止循环
int LastState=-1;                //记录上一个状态
bool flag=true;                  //ture表示船在左岸
vector<vector<state>> answer;    //解集
vector<state> temp;
state Stack[MAXSIZE];            //栈,用于DFS
int f=0,r=0;                     //栈顶与栈底
int A,B;                         //记录传教士与野人初始人数

int DFS(int M,int C,int m,int c);
int judge(int M,int C,int m,int c);
int change_judge(int M,int C,int m,int c,int met);
int if_repeat(int M,int C,bool f);
int disp();


搜索函数:

<span style="font-size:18px;">int DFS(int M,int C,int m,int c)                      //并不是典型的DFS,同一节点允许重复遍历
{
    int X=M,Y=C,x=m,y=c;
    state index;
    judge(X,Y,x,y);                                   //初始情况进栈
    while(r!=f)
    {
        index=Stack[--r];
        X=index.person;
        Y=index.wild;
        x=M-X;
        y=C-Y;
        temp.push_back({X,Y,index.boat,index.method,index.Last});
        LastState++;
        LastMethod=index.method;
        if((!flag&&X==0&&Y==0))                       //全部运输过去
        {
            answer.push_back(temp);
            if(r==f)
                break;
            else if(r!=f)
            {
                state t1;
                t1=temp.back();
                while(Stack[r-1].Last!=t1.Last)       //将解集暂存数组temp中栈顶状态后的状态删除
                {
                    temp.pop_back();
                    t1=temp.back();
                }
                temp.pop_back();
                index=Stack[--r];
                temp.push_back({index.person,index.wild,index.boat,index.method,index.Last});
                LastMethod=index.method;
                LastState=index.Last;
                LastState++;
                flag=index.boat;
                X=index.person;
                Y=index.wild;
                x=M-X;
                y=C-Y;
            }
        }
        if(!judge(X,Y,x,y))
        {
            if(r!=f)
            {
                state t2;
                t2=temp.back();
                while(Stack[r-1].Last!=t2.Last)
                {
                    temp.pop_back();
                    t2=temp.back();
                }
                temp.pop_back();
                flag=Stack[r-1].boat;
                LastState=Stack[r-1].Last;
            }
        }
    }
    if(0==answer.size())
        return 0;
    else
        return 1;
}</span>


可能状态进栈:

<pre name="code" class="cpp">int judge(int M,int C,int m,int c)                    //将下一步可能状态进栈
{
    int signal=0;
    if(1==flag)
    {
        flag=!flag;
        if(change_judge(M-1, C ,m+1, c,1)&&(if_repeat(M-1,C,flag)))
        {
            Stack[r++]={M-1,C,flag,1,LastState};
            signal=1;
        }
        if(change_judge(M-2,C,m+2, c, 2)&&(if_repeat(M-2,C,flag)))
        {
            Stack[r++]={M-2,C,flag,2,LastState};
            signal=1;
        }
        if(change_judge(M-1, C-1,m+1, c+1, 3)&&(if_repeat(M-1,C-1,flag)))
        {
            Stack[r++]={M-1,C-1,flag,3,LastState};
            signal=1;
        }
        if(change_judge(M, C-1,m, c+1, 4)&&(if_repeat(M,C-1,flag)))
        {
            Stack[r++]={M,C-1,flag,4,LastState};
            signal=1;
        }
        if(change_judge(M, C-2,m, c+2, 5)&&(if_repeat(M,C-2,flag)))
        {
            Stack[r++]={M,C-2,flag,5,LastState};
            signal=1;
        }
    }
    else
    {
        flag=!flag;
        if(change_judge(M+1, C ,m-1, c,1)&&(if_repeat(M+1,C,flag)))
        {
            Stack[r++]={M+1,C,flag,1,LastState};
            signal=1;
        }
        if(change_judge(M+2,C,m-2, c, 2)&&(if_repeat(M+2,C,flag)))
        {
            Stack[r++]={M+2,C,flag,2,LastState};
            signal=1;
        }
        if(change_judge(M+1, C+1,m-1, c-1, 3)&&(if_repeat(M+1,C+1,flag)))
        {
            Stack[r++]={M+1,C+1,flag,3,LastState};
            signal=1;
        }
        if(change_judge(M, C+1,m, c-1, 4)&&(if_repeat(M,C+1,flag)))
        {
            Stack[r++]={M,C+1,flag,4,LastState};
            signal=1;
        }
        if(change_judge(M, C+2,m, c-2, 5)&&(if_repeat(M,C+2,flag)))
        {
            Stack[r++]={M,C+2,flag,5,LastState};
            signal=1;
        }
    }
    return signal;
}

int change_judge(int M,int C,int m,int c,int met)     //判断接下来的可能状态是否非法
{
    if( M<0||C<0||m<0||c<0)    //非法
        return 0;
    if( M>A||C>B||m>A||c>B)    //非法
        return 0;
    if((M==A)&&(C==B))         //防止回溯到初始节点
        return 0;
    if( (M&&C>M) ||(m&&c>m))   //野人会吃牧师
        return 0;
    if(LastMethod==met)
        return 0;
    return 1;
}

int if_repeat(int M,int C,bool f)                     //判断接下来的可能状态是否与栈中已有状态重复,防止回溯
{
    for(int x=0;x<r;x++)
        if((Stack[x].person==M)&&(Stack[x].wild==C)&&(Stack[x].boat==f))
            return 0;
    for(unsigned int x=0;x<temp.size();x++)
        if((temp[x].person==M)&&(temp[x].wild==C)&&(temp[x].boat==f))
            return 0;
    return 1;
}

 
输出解集: 

int disp()                                             //输出解集
{
    printf("一共有%d种解法\n",answer.size());
    int m,n;
    for(m=0;m<answer.size();m++)
    {
        printf("第%d种解法:\n",m+1);
        printf("(%d,%d) boat=left\n",A,B);
        printf("%d\n",answer[m].size());
        for(n=0;n<answer[m].size();n++)
        {
            if(1==answer[m][n].method)
                cout<<"(1,0)"<<endl;
            else if(2==answer[m][n].method)
                cout<<"(2,0)"<<endl;
            else if(3==answer[m][n].method)
                cout<<"(1,1)"<<endl;
            else if(4==answer[m][n].method)
                cout<<"(0,1)"<<endl;
            else if(5==answer[m][n].method)
                cout<<"(0,2)"<<endl;
            if(answer[m][n].boat)
                printf("(%d,%d) boat=left\n",answer[m][n].person,answer[m][n].wild);
            else
                printf("(%d,%d) boat=right\n",answer[m][n].person,answer[m][n].wild);
        }
    }
    return 1;
}

main函数:

int main()
{
    printf("请输入传教士人数:");
    cin>>A;
    printf("请输入野人人数:");
    cin>>B;
    if(DFS(A,B,0,0))
        disp();
    else
        cout << "Can not find the solution."<<endl;
    return 0;
}


思路上没什么特别之处,DFS非递归。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值