关于上一篇的传教士与野人过河问题,递归固然精妙,但是只能输出一个解,如果想递归还要输出所有解,限于水平我确实想不出什么好办法。
作为人工智能课程的作业,我写了一个非递归的方法,目前只对几种情况做了检验可以输出所有解。
作为菜鸟,开始的时候在网上搜索确实好些理论都看不懂,所以在此把我的思路写在这里,不见得无暇,只为抛砖引玉。
定义部分:
#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非递归。