视频教程地址:https://www.bilibili.com/video/av12642530/#page=19
问题:

//人狼菜羊过河问题
//==============================================================
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
bool farmer(int status) //获取每个角色的位置,0表示在起始岸,1表示在目标岸
{
return ((status & 0x08) != 0);
}
bool wolf(int status)
{
return ((status & 0x04) != 0);
}
bool cabbage(int status)
{
return ((status & 0x02) != 0);
}
bool goat(int status)
{
return ((status & 0x01) != 0);
}
bool safe(int status) //判断当前起始岸状态是否安全
{
if ((goat(status) == cabbage(status)) &&
(goat(status) != farmer(status)))
return false;
if ((goat(status) == wolf(status)) &&
(goat(status) != farmer(status)))
return false;
return true;
}
int main()
{
int movers , status , newstatus; //movers表示每次过河,人要携带的角色(包括人只身一人过河),值为1表示这个角色发生了一次过河行动
//status表示起始岸状态,初始为0000,顺序为人狼菜羊,newstatus表示中间可到达状态
vector<int> route(16, -1); //,顺序表,存储已经访问过的状态(访问过就不能再访问了)
queue<int> moveTo; //存储可以安全到达的中间状态
moveTo.push(0x00); //0000是起始岸的开始状态,四位分别代表人狼羊菜
route[0] = 0; //route第一位存储0,表示已经访问过,-1表示没有访问过
while (!moveTo.empty() && route[15] == -1)
{
status = moveTo.front();
moveTo.pop();
for (movers = 1; movers <= 8; movers <<= 1) //要携带的角色
{
if (farmer(status) == (bool)(status & movers)) //要携带的角色必须和人在同一侧
{
newstatus = status ^ (0x08 | movers); //这里的按位异或操作实现了渡过去和返回的操作
if (safe(newstatus) && (route[newstatus] == -1)) //状态是否安全
{
route[newstatus] = status;
moveTo.push(newstatus);
}
}
}
}
if (route[15] != -1) //反向打印出结果
{
cout << "The reverse path is:" << endl;
for (int status = 15; status >= 0; status = route[status])
{
cout << "The status is :" << status << endl;
if (status == 0) break;
}
}
else
cout << "No solution." << endl;
while(1);
}
总结一下:在解决这道问题时,首先是问题抽象(找出题目中的约束条件),再而是数据抽象(找出合适的数据结构来表示题目中的各种状态),最后将约束条件和数据结构结合在一起得到最终的算法
上面的用按位异或实现渡河和返回的操作很精髓~