热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

一道有意思的编程思考题:【妖怪和僧人过河题目】

无意中看到这么一道题,觉得很有意思,问题以下:有三个和尚和三个妖怪要应用唯一的一条小船过河,这条小船一次只能载两个人,同时,无论是在河的两岸照样在船上,只需妖怪的数目大于和尚的数目

无意中看到这么一道题,觉得很有意思,问题以下:

有三个和尚和三个妖怪要应用唯一的一条小船过河,这条小船一次只能载两个人,同时,无论是在河的两岸照样在船上,只需妖怪的数目大于和尚的数目,妖怪们就会将和尚吃掉。如今须要挑选一种过河的部署,保证和尚和妖怪都能过河且和尚不能被妖怪吃掉。

看完问题,起首想到的是暴力搜刮。不断地穷举下一步的能够性,直到终究杀青目的。由于搜刮过程当中能够会有反复的状况,所以须要对状况举行哈希。

怎样示意当前的状况?起首想到的是用多维数组举行哈希。我们能够用一个四维数组(实在完全能够用二维,左侧和尚妖怪的数目肯定后,响应地就能够盘算右侧了,须要多一步运算),假定左岸和尚和妖怪数目分别是 a 和 b,右岸和尚妖怪数目分别是 c 和 d,那末我们能够用 [a][b][c][d]=true 示意这类状况,也就是该状况已被搜刮过了。如许做另有个破绽,船在摆布双方是差别的状况,所以还须要一个维度来示意船的位置,那末能够如许,增添一维,用 [a][b][c][d][1]=true 示意船在左侧的状况,用 [a][b][c][d][0]=true 示意船在右侧的状况。如许来示意状况是完全能够的,然则尽人皆知 Javascript 下示意多维数组异常的贫苦,所以进一步思索能不能将状况紧缩。

继承看,最开始时的状况,如上能够示意为 [3][3][0][0][1],以后的搜刮过程当中,状况中的数字不能够大于 3,也就是数字的范围在 0~3 中,这不是光秃秃的四进制数吗?因而我们能够将该状况紧缩到一个四进制数 330001 中,然则四进制毕竟操纵起来不大轻易,能不能转为二进制?答案很明显,一个四进制数能够拆成两个二进制,如许就好办了,将四进制的 33001 能够转成二进制 1111000001,二进制的种种运算就轻易多了!

斟酌到末了一个维度的特殊状况,终究我决定将前四个维度用一个二进制来处置惩罚,第五个维度(船的位置)零丁处置惩罚,用一个二维数组举行状况哈希。

很显然,我们须要能将数组和二进制数交换的函数。

简朴写了两个交换函数,将数组转为数字的。比方将 [3, 3, 0, 0] 转为二进制大小为 11110000 的数字:

// array to number
function aton(a) {
var sum = 0;
for (var i = a.length; i--; ) {
var index = 3 - i
, item = a[i];
(item & 1) && (sum |= (1 <<(index <<1)));
(item & 2) && (sum |= (1 <<((index <<1) | 1)));
}
return sum;
}

将数字转为数组的,为以上函数的逆运算:

// number to array
function ntoa(n) {
var a = [];
for (var i = 0; i <4; i++) {
var num = 0
, index = 3 - i;
num |= n & (1 <<(index <<1)) ? 1 : 0;
num |= n & ((1 <<((index <<1) | 1))) ? 2 : 0;
a.push(num);
}
return a;
}

接下去就异常简朴了,举行深度优先搜刮,每次搜刮罗列下一个能够的状况,对该状况举行哈希,并把该状况存入答案数组中,罗列完举行回溯。

// pos == 1 示意船在左侧
// pos == 0 示意船在右侧
function dfs(num, pos) {
if (hash[num][pos])
return;
hash[num][pos] = true;
var a = ntoa(num);
var l_sNum = a[0];
var l_yNum = a[1];
var r_sNum = a[2];
var r_yNum = a[3];
pos ? a.push('left') : a.push('right');
ans.push(a);
if (num === 15) { // [0, 0, 3, 3]
// 打印答案
ans.concat().forEach(function(item) {
console.log(item.toString() + '->');
});
console.log('------------------');
// backtrace
hash[num][pos] = false;
ans.pop();
return;
}
// left to right
if (pos) {
for (var i = 0; i <= l_yNum; i++) // 妖怪过河数
for (var j = 0; j <= l_sNum; j++) { // 和尚过河数
if (i + j === 0)
continue;
// 船上是不是平安
if (!checkIfSafe(j, i))
continue;
// 左岸是不是平安
if (!checkIfSafe(l_sNum - j, l_yNum - i))
continue;
// 右岸是不是平安
if (!checkIfSafe(r_sNum + j, r_yNum + i))
continue;
if (i + j > 2)
break;
// 过河后的数据
var b = [l_sNum - j, l_yNum - i, r_sNum + j, r_yNum + i];
dfs(aton(b), 0);
}
} else { // right to left
for (var i = 0; i <= r_yNum; i++)
for (var j = 0; j <= r_sNum; j++) {
if (i + j === 0)
continue;
if (!checkIfSafe(j, i))
continue;
if (!checkIfSafe(r_sNum - j, r_yNum - i))
continue;
if (!checkIfSafe(l_sNum + j, l_yNum + i))
continue;
if (i + j > 2)
break;
// 过河后的数据
var b = [l_sNum + j, l_yNum + i, r_sNum - j, r_yNum - i];
dfs(aton(b), 1);
}
}
// backtrace
hash[num][pos] = false;
ans.pop();
}

简朴地看下深度优先搜刮的函数,每次依据船地点的位置,罗列下个状况值。这里我写了个 checkIfSafe 函数来推断当前数目的和尚和妖怪在一起,会不会有风险。函数异常简朴:

function checkIfSafe(sNum, yNum) {
return sNum === 0 || sNum >= yNum;
}

末了的末了,解法有四种,大概是这个模样:

3,3,0,0,left->
2,2,1,1,right->
3,2,0,1,left->
3,0,0,3,right->
3,1,0,2,left->
1,1,2,2,right->
2,2,1,1,left->
0,2,3,1,right->
0,3,3,0,left->
0,1,3,2,right->
1,1,2,2,left->
0,0,3,3,right->
------------------
3,3,0,0,left->
2,2,1,1,right->
3,2,0,1,left->
3,0,0,3,right->
3,1,0,2,left->
1,1,2,2,right->
2,2,1,1,left->
0,2,3,1,right->
0,3,3,0,left->
0,1,3,2,right->
0,2,3,1,left->
0,0,3,3,right->
------------------
3,3,0,0,left->
3,1,0,2,right->
3,2,0,1,left->
3,0,0,3,right->
3,1,0,2,left->
1,1,2,2,right->
2,2,1,1,left->
0,2,3,1,right->
0,3,3,0,left->
0,1,3,2,right->
1,1,2,2,left->
0,0,3,3,right->
------------------
3,3,0,0,left->
3,1,0,2,right->
3,2,0,1,left->
3,0,0,3,right->
3,1,0,2,left->
1,1,2,2,right->
2,2,1,1,left->
0,2,3,1,right->
0,3,3,0,left->
0,1,3,2,right->
0,2,3,1,left->
0,0,3,3,right->
------------------

完全代码点 这里。


推荐阅读
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 开发笔记:计网局域网:NAT 是如何工作的?
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了计网-局域网:NAT是如何工作的?相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 背景应用安全领域,各类攻击长久以来都危害着互联网上的应用,在web应用安全风险中,各类注入、跨站等攻击仍然占据着较前的位置。WAF(Web应用防火墙)正是为防御和阻断这类攻击而存在 ... [详细]
author-avatar
保佑想-回丽水的阿卉
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有