题目描述:农夫需要把狼、羊、菜和自己运到河对岸去,只有农夫能够划船,而且船比较小,除农夫之外每次只能运一种东西,还有一个棘手问题,就是如果没有农夫看着,羊会偷吃菜,狼会吃羊。请考虑一种方法,让农夫能够安全地安排这些东西和他自己过河。

想这个问题一连想了好几天,本人没有系统的学过算法,有些概念也不是很清楚,只因解决问题为目标。

尝试过图论解决,但用floyed算法只能算出最短路径值,如何输出过程,一直没想出好的解决方法。

然后看了下面这篇文章,尝试抛弃图论,用树的思想来解决这个问题。建议阅读下面代码时,先看看这篇文章。

参考资料:

在写代码时,本人采用了上述文章中的思想,又借鉴了图论中存储结点的一些方法。

我觉得这样写应该非常容易看懂了。具体思路见代码。

1 #include <stdio.h>
 2 #define INF 9999
 3 //8个动作
 4 char *action[8]={"农夫单独过河","农夫带狼过河","农夫带羊过河","农夫带菜过河",
 5                  "农夫单独返回","农夫带狼返回","农夫带羊返回","农夫带菜返回"};
 6 //10种状态
 7 char *state[10]={"人狼羊菜","人狼羊","人狼菜","人羊菜","人羊","狼菜","狼","羊","菜","空"};
 8 
 9 //状态转换规则:GA[i][j]=k 表示【状态i】可以通过【动作k】转换到【状态j】,GA[i][j]=INF表示不可直接转换 
10 int GA[10][10]={INF,INF,INF,INF,INF,  2,INF,INF,INF,INF,
11                 INF,INF,INF,INF,INF,INF,  2,  1,INF,INF,
12                 INF,INF,INF,INF,INF,  0,  3,INF,  1,INF,
13                 INF,INF,INF,INF,INF,INF,INF,  3,  2,INF,
14                 INF,INF,INF,INF,INF,INF,INF,  0,INF,  2,
15                   6,INF,  4,INF,INF,INF,INF,INF,INF,INF,
16                 INF,  6,  7,INF,INF,INF,INF,INF,INF,INF,
17                 INF,  5,INF,  7,  4,INF,INF,INF,INF,INF,
18                 INF,INF,  5,  6,INF,INF,INF,INF,INF,INF,
19                 INF,INF,INF,INF,  6,INF,INF,INF,INF,INF};
20                 
21 //记录每一步的动作 
22 int record_action[20];
23 //记录每一步动作后的状态
24 int record_state[20]; 
25 
26 //搜索从第step步开始、第i个结点到第n个结点的过程(step从0算起)
27 void search(int i,int n,int step)
28 {
29     int k;//动作
30     int j;//可能要转换到的状态 
31     if(i==n)
32     {
33         for(k=0;k<step;k++)
34             printf("step %d: %s,左岸还剩 %s\n",k+1,action[record_action[k]],state[record_state[k]]);
35         printf("step count:%d\n\n",step);
36         return;
37     }
38     //查找在当前【状态i】下能转换到的【其它状态j】,并且【状态j】不能在之前出现过 
39     //查找时可能会出现多个 j,所以这是一个多叉树 
40     for(k=0;k<8;k++)
41     {
42         for(j=0;j<10;j++)
43             if(GA[i][j]!=INF&&GA[i][j]==k)//判断状态i能否通过动作k转换到状态j 
44             {
45                 int m;
46                 //下面这个循环是判断状态j在之前是否出现过 
47                 for(m=0;m<step;m++)
48                     if(j==record_state[m])break;
49                 if(m<step)continue;
50                 //如果j满足前面所有条件,则记录这一步 
51                 record_action[step]=k;    //第step步所使用的动作 
52                 record_state[step]=j;    //第step步所转换的状态 
53                 search(j,n,step+1);        //继续搜索下一步 
54             }
55     }
56         
57 }
58 int main()
59 {
60     search(0,9,0);
61     return 0;
62 }