高一的时候,同学(老友)问过这个题,我现在还记得他当时的话语:“这道题,我们那边的一个大学生想了三天都没想出来,呵呵,让我解决了,厉害吧,哈哈。。。”。当时,我也是冲着他那句“大学生三天都没想出来”,才兴致勃勃地答应挑战的,可惜,当时终究是没想出来,最后,只好逼着他讲答案。当然,经历过大学的人都知道,其实大学生也就那样,大多很普通,无须过高的评价。
题意大致如下:
有6个怪物AaBbCc,ABC是大怪物,abc是小怪物,Aa、Bb、Cc是亲子关系,当小怪物的父亲不在身边时,别的大怪物会吃这个小怪物,大怪物不会吃自己的孩子,现在这6个怪物要过河,这边有一条船,船最多可载2只大怪物,或3只小怪物,当然也可以载1只大怪物和1只小怪物,其中知道ABCa会划船,bc不会,想办法让6个怪物都安全到对岸。
大学后,我开始尝试用编程来解决它,但每每不能成功,最大的难点是,我不知如何把实际问题抽象出来。这样,每过一年,我都会再尝试一次。
“辛波那契数列”也是我大学时遇到的一个难题,不过,在去年的时候已经解决了,但在我的博客中居然没有相关信息,所以上篇文章再写了这个问题。
想到“怪物过河问题”是我之前想解决而又未解决的最后一个问题,昨天晚上又开始了新的尝试,还好这次编码非常顺利,终于,抽象出问题来了,中间的一些小的编码漏洞,和个别特殊情况引发的思维漏洞,让我找了一个通宵,早上睡了4个小时,出去购物回来已是中午2点,继续找,终于全部把漏洞全补好了。
我的实现如下:
#include <list>
#include <string>
#include <iostream>
using namespace std;
struct Monster
{
char place;
const char name;
const bool paddle;
const short weight;
};
Monster monster[6] =
{
{ 'H', 'A', true, 3 },
{ 'H', 'B', true, 3 },
{ 'H', 'C', true, 3 },
{ 'H', 'a', true, 2 },
{ 'H', 'b', false, 2 },
{ 'H', 'c', false, 2 }
};
int left_count = 6; /* 剩余需要过河的怪物 */
const int boat_load_weight = 6; /* 船的最大载重量 */
list<int> move_index_list; /* 记录每次过河的怪物 */
static bool check(int, char);
static bool move(char, char);
static bool try_move(int, char, char);
static void change_place(int, char);
static void display_way();
void display_state(bool go);
/*
* 检测此次过河方案是否安全
*/
bool check(int current_move_index, char to)
{
/*
* 不允许出现相同的怪物做往返过河的动作
* 比如: Xx(H->T), Xx(H<-T)
* 下面特例也需视为此情形:
* 1. Yy(->), Zz(<-))
* 2. Zz(->), Yy(<-))
*/
if (!move_index_list.empty())
{
int last_move_index = move_index_list.back();
if (last_move_index == current_move_index ||
(25 == last_move_index &&
36 == current_move_index) ||
(36 == last_move_index &&
25 == current_move_index))
{
return(false);
}
}
/* 检查各小怪物 (xyz) 是否安全 */
for (int i = 3; i < 6; ++i)
{
const Monster & young = monster[i];
const Monster & old = monster[i - 3];
if (young.place == old.place)
{
continue; /* 此时 young 必定安全 */
}
for (int j = 0; j < 3; ++j)
{
if (i - 3 == j)
{
continue;
}
/*
* 1.检查船在河中时, young 是否有安全
* 2.检查船到彼岸后, young 是否有安全
*/
const Monster & enemy = monster[j];
if (young.place == enemy.place ||
(to == young.place &&
'B' == enemy.place &&
'B' != old.place) ||
('B' == young.place &&
to == enemy.place &&
to != old.place))
{
return(false);
}
}
}
if ('T' == to) /* 'T' 代表 There */
{
return(true);
}
/*
* (否则)如果船是返回方向的, 此时
* 不能变成最初的状态, 即:
* 不能出现所有怪物都回来的现象
* 比如:
* xyz(H->T), xy(H<-T), x(H->T), xy(H<-T)
* 且不论上面四步是在做无用功,
* 最可怕的是会使搜索陷入无限递归中
*/
for (int j = 0; j < 6; ++j)
{
co