商人安全渡河问题
问题描述
三名商人携带随从乘船,一次最多过两人,在任一岸随从人数大于商人,则随从杀人越货,问商人如何安全渡河?(不妨设最初在西岸)
思路
可以看出这是一个迷宫问题,但是不同于数据结构中的普通的二维的迷宫问题,此问题中需要考虑的参数还有:船在东岸还是在西岸。所以我们考虑将状态设定为一个三维的数组。采用迷宫问题的解决方式——递归来解决这个问题。
而我们知道,迷宫问题中,需要知道的有:可以到达的状态集合、可以进行的决策集合。在设置初始状态和终止状态后,只需要使用函数递归即可寻找迷宫的解。递归函数中,首先需要判定当前状态是否是终止状态,若是则退出递归,否则继续。接着遍历决策集合,判断执行决策后是否是安全状态,否则此决策丢弃。如果是安全状态,则修改可以到达的状态集合,继续前进(递归)。
基础设定
设置状态为三维的数组(a,b,c),a,b分别表示未渡河商人个数和随从个数,c表示此时船在东岸或者西岸(用0/1 表示,0为东,1为西)
设置决策为三维的数组(m,n,1),m,n分别表示船上商人个数和随从个数,而第三个参数下文的操作中会提到。
安全状态
安全状态最初即为可以保证在任何一个岸边商人数都不少于随从个数的状态集合。在递归层数增加时,安全状态应该剔除当前的状态以避免造成死循环(也即是在迷宫问题的邻接矩阵中每次经过节点后把可通过状态改为不可经过)。为实现这种功能,设计两个集合,S用来统计最初的安全状态,S2用来统计当前递归下,已经经过的安全状态。
不妨设最初状态为(3,3,1),终止状态为(0,0,0)
决策
我们这样来定义决策函数:
奇数次渡河时,未渡河的人数是减去船上的人数的;而偶数次渡河时,是加上船上人数的。也即是,当船在西岸时,做减法,否则是做加法。而状态变量中的第三个参数就是记录船在哪个岸的。于是我们这么设计函数:tmp=s_now+(-1^(s_now(1,3))*d_now;
源代码
merchant.m:
clear;clc;
global S;
global D;
S = [3 3 0;3 3 1;3 2 0; 3 2 1;3 1 0;3 1 1;