先上代码:
const LinkedList = require("../../../util/LinkedList"); function RiverPuzzle() { var lDeadSet = new Set([120003,23100]), rDeadSet = new Set([100023,3120]), visited = new Set(); var queue = new LinkedList(); var step = []; var curr = 123; var end = ''; var pre = new Map(); queue.add(curr); visited.add(curr); this.path = function () { console.log('path: ' + pre); var res = []; var c = end; debugger while (c != pre.get(c)) { res.push(c); c = pre.get(c); } res.reverse(); return res; } var bfs = function () { while (!queue.isEmpty()) { var cur = queue.remove(); var nexts = []; var i = parseInt(cur % 1000 / 100) * 100; var j = parseInt(cur % 100 / 10) * 10; var k = parseInt(cur % 10); nexts.push(cur - i + i * 1000); nexts.push(cur - j + j * 1000); nexts.push(cur - k + k * 1000); var x = parseInt(cur / 100000) * 100000; var y = parseInt((cur - x) / 10000) * 10000; var z = parseInt((cur - y) / 1000) * 1000; nexts.push(cur - x + x / 1000); nexts.push(cur - y + y / 1000); nexts.push(cur - z + z / 1000); // 从右边往左边运 if (step.length == 0) { for (var i = 0; i < 3; i++) { var next = nexts[i]; // 若next没被访问过并且不在死亡数字中 if (!visited.has(next) && !rDeadSet.has(next)) { queue.add(next); visited.add(next); pre.set(next, cur); // 运完了后,发现左边有死亡数字,则触发从左边往右边运 if (lDeadSet.has(next)) { step.push(1); } } if (next == 123000) { end = next; return; } } } else { for (var i = 3; i < 6; i++) { var next = nexts[i]; if (!visited.has(next) && !lDeadSet.has(next)) { queue.add(next); visited.add(next); pre.set(next, cur); step.splice(0,1); } if (next == 123000) { end = next; return; } } } } } bfs(curr); } var river = new RiverPuzzle(); console.log(river.path());
我实现的思路是这样的:采用了老师前面介绍的解密码锁和装水的思路。狼和羊在一边或羊和菜在一边,那么就是死锁,也就是开锁题目的DeadSet,只不过它又是把DeadSet分2部分存储。说它为何又和装水的问题很像呢?是因为河的左岸和右岸可以看成是2个水桶,但是它又和水桶问题又有点区别,区别在于水桶可以从外部接水,我们这个题目它不能从外部引入物件,因为题目只给你3个动物,不会多出别的数据。我们在定义狼是1,羊是2,菜是3,那么这里初始状态就是000123,也就是123,代表动物都在左边岸上,我们要让最终状态是123000。这里注意,数据格式是这样的:xxx,xxx,逗号左边是左岸,右边是右岸,数字移位置只能是:1在百位或者10W位,2只能在十位或万位,3只能在个位和千位来回调换,这样就可以用一个数字来表示状态了。
nexts数据也分2部分,前3部分数据是从右岸向左岸运动物,后3部分是从左岸向右岸运动物。
这里右考虑到,加入船和农夫再有死锁对应的岸边,是可以让数据通过验证的,所以我把死锁的状态分为左岸死锁和右岸死锁两部分,举个例子,当我运一只动物到对岸去(从右边数据向左边数据送数据),这时对岸2个动物虽然是不能共存的,但是我们暂时不去管它,只是在step中存入一个状态数据告诉程序农夫在下轮循环中要带一个动物回去,然后在下轮循环处理中农夫会带一个动物回去,也就是从左岸向右岸运动物,当step为空的时候就表示左岸的数据没死锁了,然后在下一轮循环中继续从右岸向左岸运动物,知道达到终止状态程序结束。
程序的其它部分和之前的代码一样,没什么好说的。
刚看了别人的代码发现我这里只需要01占位就可以了。