分析
过河时,河的一岸减少,另一岸相应增加
只有五种过河情况,我们按照限制条件和目的情况已经分情况递归即可
DFS时,我们要弄清有哪些限制条件 , 我们的目的 ,以及过程的情况来编写递归:
限制条件:
无论在哪一岸,必须满足野人数小于等于传教士人数才能避免吃人情况
人数不论哪一人种哪一岸都不能超过初始人数,不能小于0
目的:
河对岸的野人数等于初始野人人数
河对岸的传教士人数等于初始传教士人数
过程情况:
只有五种过河情况:
1.一个野人过河
2.一个传教士过河
3.一个传教士一个野人过河
4.两个传教士
5.两个野人
因为有船的情况,此时我们已经可以同时对两岸进行递归,但是为了简化代码,我们可以根据船在哪一岸来执行相应的人数增减,即至船初始化为1,当到达对岸时,不断 * -1 来改变船的状态来区分在哪一岸来执行相应人数增减
具体代码实现已在代码中标明注释
#include <bits/stdc++.h>
using namespace std;
const int MAX = 1000;
struct Statement
{
int Left_cjs;
int Right_cjs;
int Left_yr;
int Right_yr;
int Cuan;
};
Statement Old[MAX]; //状态数组
int dex = 0;
int Sum = 0;
int Start_cjs, Start_yr; //初始传教士,初始野人
int CrossRiver(Statement Now)
{
//是否达到目标转态
if (Now.Right_cjs == Start_cjs && Now.Right_yr == Start_yr)
{
Sum++;
return 0;
}
//检查重复操作
for (int i = 0; i < dex; i++) //遍历整个过程
if (Now.Left_cjs == Old[i].Left_cjs && Now.Left_yr == Old[i].Left_yr && Now.Cuan == Old[i].Cuan)
return 0;
//检查人数
if (Now.Left_cjs < 0 || Now.Left_yr < 0 || Now.Right_cjs < 0 || Now.Right_yr < 0 || Now.Left_cjs > Start_cjs || Now.Left_yr > Start_yr || Now.Right_cjs > Start_cjs || Now.Right_yr > Start_yr) //不小于0,不大于初始
return 0;
//是否发生吃人
if ((Now.Left_cjs < Now.Left_yr && Now.Left_cjs != 0) || (Now.Right_cjs < Now.Right_yr && Now.Right_cjs != 0)) //当有传教士在任意一边且野人数多余传教士
{
return 0;
}
//临时节点
Statement temp;
//一个野人
temp.Left_cjs = Now.Left_cjs;
temp.Left_yr = Now.Left_yr - 1 * Now.Cuan;
temp.Right_cjs = Now.Right_cjs;
temp.Right_yr = Now.Right_yr + 1 * Now.Cuan;
temp.Cuan = (-1 * Now.Cuan);
dex++;
Old[dex] = temp; //加入状态数组
CrossRiver(temp);
dex--;
//一个传教士过河
temp.Left_cjs = Now.Left_cjs - 1 * Now.Cuan;
temp.Left_yr = Now.Left_yr;
temp.Right_cjs = Now.Right_cjs + 1 * Now.Cuan;
temp.Right_yr = Now.Right_yr;
temp.Cuan = (-Now.Cuan);
dex++;
Old[dex] = temp;
CrossRiver(temp); //传递状态
//回溯,temp自动覆盖
dex--;
//一个野人,一个传教士过河
temp.Left_cjs = Now.Left_cjs - 1 * Now.Cuan;
temp.Left_yr = Now.Left_yr - 1 * Now.Cuan;
temp.Right_cjs = Now.Right_cjs + 1 * Now.Cuan;
temp.Right_yr = Now.Right_yr + 1 * Now.Cuan;
temp.Cuan = (-Now.Cuan);
dex++;
Old[dex] = temp;
CrossRiver(temp);
//回溯,temp自动覆盖
dex--;
//两个传教士过河
temp.Left_cjs = Now.Left_cjs - 2 * Now.Cuan;
temp.Left_yr = Now.Left_yr;
temp.Right_cjs = Now.Right_cjs + 2 * Now.Cuan;
temp.Right_yr = Now.Right_yr;
temp.Cuan = (-Now.Cuan);
dex++;
Old[dex] = temp;
CrossRiver(temp); //传递状态
//回溯,temp自动覆盖
dex--;
//两个野人过河
temp.Left_cjs = Now.Left_cjs;
temp.Left_yr = Now.Left_yr - 2 * Now.Cuan;
temp.Right_cjs = Now.Right_cjs;
temp.Right_yr = Now.Right_yr + 2 * Now.Cuan;
temp.Cuan = (-Now.Cuan);
dex++;
Old[dex] = temp;
CrossRiver(temp); //传递状态
//回溯,temp自动覆盖
dex--;
return 0;
}
int main()
{
cin >> Start_cjs;
cin >> Start_yr;
//初始化
Old[dex].Left_cjs = Start_cjs;
Old[dex].Left_yr = Start_yr;
Old[dex].Right_cjs = 0;
Old[dex].Right_yr = 0;
Old[dex].Cuan = 1;
//开始
CrossRiver(Old[dex]); //传递状态
cout << Sum;
system("pause");
}