过河问题大家都知道,不多说了.
解决这个问题的经典方法就是使用有限状态机. 根据人,狼,羊,菜,在不同河岸,可以抽象出N种不同的状态.某些状态之间可以转换. 这些转换就是运算了. 我们的目的就是找到一组这样的运算,可以从初始状态转换到终止状态. 其间的状态必需都是合法的. C++代码如下:
/*-------------------------------------
农夫,狼,羊, 菜,过河
--------------------------------------*/
#include <list>
#include <iostream>
enum PLACE
{
NO, // 没有过河的
YES, // 已经过河了
};
// 状态
typedef struct
{
PLACE man; // 人的状态
PLACE wolf; // 狼的状态
PLACE sheep; // 羊有状态
PLACE menu; // 菜的状态
} STATUS;
const STATUS c_start = {NO,NO,NO,NO}; // 起始状态
const STATUS c_end = {YES,YES,YES,YES}; // 终止状态
// 结点(保存转换路径)
typedef struct TURN{
STATUS status;
TURN* p;
}TURN;
typedef std::list<TURN> LIST_TURN;
typedef std::list<TURN*> LIST_NODE;
// 判断两个状态是否一致
bool operator == (const STATUS& sa, const STATUS& sb)
{
return sa.man == sb.man && sa.wolf == sb.wolf &&
sa.sheep == sb.sheep && sa.menu == sb.menu;
}
// 查找状态是否已经存在
bool Find(LIST_TURN& ls, const STATUS& s)
{
LIST_TURN::iterator it = ls.begin();
for(;it!=ls.end(); it++)
{
if((*it).status==s)
return true;
}
return false;
}
// 状态转换运算
enum OPERATOR
{
MAN_GO, // 人过河
MAN_GO_WITH_WOLF, // 人带狼过河
MAN_GO_WITH_SHEEP, // 人带羊过河
MAN_GO_WITH_MENU, // 人带菜过河
MAN_BACK, // 人回来
MAN_BACK_WITH_WOLF, // 人带狼回来
MAN_BACK_WITH_SHEEP, // 人带羊回来
MAN_BACK_WITH_MENU, // 人带菜回来
OP_FIRST = MAN_GO,
OP_LAST = MAN_BACK_WITH_MENU,
};
// 状态转换
bool StatusTurn(const STATUS& src, OPERATOR op, STATUS& desc)
{
switch(op)
{
case MAN_GO: // 人过河
if(src.man == NO) {
desc = src;
desc.man = YES;
return true;
}
break;
case MAN_GO_WITH_WOLF: // 人带狼过河
if(src.man == NO && src.wolf == NO)
{
desc = src;
desc.man = YES;
desc.wolf = YES;
return true;
}
break;
case MAN_GO_WITH_SHEEP: // 人带羊过河
if(src.man == NO && src.sheep == NO)
{
desc = src;
desc.man = YES;
desc.sheep = YES;
return true;
}
break;
case MAN_GO_WITH_MENU: // 人带菜过河
if(src.man == NO && src.menu == NO)
{
desc = src;
desc.man = YES;
desc.menu = YES;
return true;
}
break;
case MAN_BACK: // 人回来
if(src.man == YES) {
desc = src;
desc.man = NO;
return true;
}
break;
case MAN_BACK_WITH_WOLF: // 人带狼回来
if(src.man == YES && src.wolf == YES) {
desc = src;
desc.man = NO;
desc.wolf = NO;
return true;
}
break;
case MAN_BACK_WITH_SHEEP: // 人带羊回来
if(src.man == YES && src.sheep == YES) {
desc = src;
desc.man = NO;
desc.sheep = NO;
return true;
}
break;
case MAN_BACK_WITH_MENU: // 人带菜回来
if(src.man == YES && src.menu == YES) {
desc = src;
desc.man = NO;
desc.menu = NO;
return true;
}
break;
}
return false;
}
// 状态检测(检测合法的状态)
bool StatusTest(const STATUS& s)
{
// 人不在的时候,狼会吃羊,羊会吃菜
if(s.man != NO){
if(s.wolf == NO && s.sheep == NO || s.sheep == NO && s.menu == NO)
return false;
}
if(s.man != YES){
if(s.wolf == YES && s.sheep == YES || s.sheep == YES && s.menu == YES)
return false;
}
return true;
}
int main()
{
LIST_TURN history; // 已经搜索过的状态
LIST_NODE active; // 需要搜索的状态
// 生成起始结点
TURN turn;
turn.status = c_start;
turn.p = 0;
history.push_back(turn);
active.push_back(&history.back());
// 初始化
bool bFind = false;
TURN* pend = 0;
// 状态转换图搜索(广度优先,求转换次数最少的路径)
while(!active.empty())
{
// 待搜索的当前结点
TURN* pact = active.front();
active.pop_front();
// 如果等于终止状态,则搜索成功
if(pact->status == c_end)
{
bFind = true;
pend = pact;
break;
}
// 计算当前状态的所有可能的下一个状态
for(OPERATOR op = OP_FIRST; op <= OP_LAST; op=(OPERATOR)(op+1))
{
TURN next;
// 下一个状态满足:
// (1) 有一个转换运算从当前状态转换到此状态
// (2) 此状态是有效的状态
// (3) 此状态是一个新状态.已经搜索过的状态不用再搜索
if(StatusTurn(pact->status, op, next.status) &&
StatusTest(next.status) && !Find(history, next.status))
{
// 为搜索图添加下一个结点
next.p = pact;
history.push_back(next);
active.push_back(&history.back());
}
}
}
// 如果找到
if(bFind)
{
// 计算路径
active.clear();
TURN* p = pend;
while(p)
{
active.push_front(p);
p = p->p;
}
// show node
for(LIST_NODE::iterator it = active.begin(); it != active.end(); it++)
{
if((*it)->status.man == NO) std::cout << "[人]"; else std::cout << "[..]";
if((*it)->status.wolf == NO) std::cout << "[狼]"; else std::cout << "[..]";
if((*it)->status.sheep == NO) std::cout << "[羊]"; else std::cout << "[..]";
if((*it)->status.menu == NO) std::cout << "[菜]"; else std::cout << "[..]";
std::cout << " <=====> ";
if((*it)->status.man == YES) std::cout << "[人]"; else std::cout << "[..]";
if((*it)->status.wolf == YES) std::cout << "[狼]"; else std::cout << "[..]";
if((*it)->status.sheep == YES) std::cout << "[羊]"; else std::cout << "[..]";
if((*it)->status.menu == YES) std::cout << "[菜]"; else std::cout << "[..]";
std::cout << std::endl;
}
}
else
{
std::cout<<"Not Found!" << std::endl;
}
return 0;
}