算法系列(一) Google方程式
2015-09-08 11:29
260 查看
用计算机穷举所有的解
以上是用人的思维方式的解题过程,如果方法正确,加上运气好(三次假设都是正 确的,避免在错误分支上浪费时间),两分钟内就可得到结果。但是考虑到更通用的情况,字母数字 没有规律,也没有可供分析的入手点和线索,比如:
AAB – BBC = CCD
这样的问题,该什么方法解决呢?只能“猜想”,用穷举的方法试探每一种猜想,对每个 字母和数字穷举所有可能的组合,直到得到正确的结果。当然,这样的力气活交给计算机做是最合适 不过了。
1. 建立数学模型
要想让计算机解决问题,就要让计算机能够 理解题目,这就需要建立一个计算机能够识别、处理的数学模型,首先要解决的问题就是建立字母和 数字的映射关系的数学模型。本题的数学模型很简单,就是一个字母二元组:{char, number}。考察 等式:
WWWDOT - GOOGLE = DOTCOM
共出现了9个不同的字母:W、D、O、T、G、L、E、C 和M,因此,最终的解应该是9个字母对应的字母二元组向量:[ {'W', 7}, {'D', 5}, {'O', 8}, {'T', 9}, {'G', 1}, {'L', 0}, {'E', 3}, {'C', 4}, {'M', 6} ]。穷举算法就是对这个字母二元组向量中每个字母二元 组的number元素进行穷举,number的穷举范围就是0-9共10个数字,当然,根据题目要求,有一些字 符不能为0,比如W、G和D。排列组合问题的穷举多使用多重循环,看样子这个穷举算法应该是9重循环
了,在每层循环中对一个字母进行从0到9遍历。问题是,必须这样吗,对于更通用的情况,不是9个字 母的问题怎么办?首先思考一下是否每次都要遍历0-9。题目要求每个字母代表一个数字,而且不重 复,很显然,对每个字母进行的并不是排列,而是某种形式的组合,举个例子,就是如果W字母占用了 数字7,那么其它字母就肯定不是7,所以对D字母遍历是就可以跳过7。进一步,假设某次遍历的字母 二元组向量中除M字母外其它8个字母已经有对应的数字了,比如:
[ {'W', 7}, {'D', 5}, {'O', 8}, {'T', 9}, {'G', 1}, {'L', 0}, {'E', 3}, {'C', 4}, {'M', ?} ] (序列-1)
那么M的可选范围 就只有2和6,显然没必要使用9重循环。
现在换一种想法,对9个二元组的向量进行遍历,可以 分解为两个步骤,首先确定第一个二元组的值,然后对剩下的8个二元组进行遍历。显然这是一种递归 的思想(分治),算法很简单,但是要对10个数字的使用情况进行标识,对剩下的二元组进行遍历时 只使用没有占用标识的数字。因此还需要一个标识数字占用情况的数字二元组定义,这个二元组可以 这样定义:{number, using},0-9共有10个数字,因此需要维护一个长度为10的数字二元组向量。数 字二元组向量的初始值是:
[{0, false}, {1, false},{2, false},{3, false},{4, false}, {5, false},{6, false},{7, false},{8, false},{9, false}] (序列-2)
每进行一重递归 就有一个数字的using标志被置为true,当字母二元组向量得到(序列-1)的结果时,对应的数字二 元组向量的值应该是:
[{0, true}, {1, true},{2, false},{3, true},{4, true},{5, true},{6, false},{7, true},{8, true},{9, true}] (序列-3)
此时遍历这个数字二元组 向量就可以知道M字母的可选值只能是2或6。
穷举遍历的结束条件是每层递归中遍历完所有 using标志是false的数字,最外一层遍历完所有using标志是false的数字就结束了算法。
根据 题目要求,开始位置的数字不能是0,也就是W、G和D这三个字母不能是0,这是一个“剪枝”条件,要 利用起来,因此,对字母二元组进行扩充成字母三元组,添加一个leading标志:{char, number, leading}。下面就是这个数学模型的C语言定义:
根据此数学模型初始化字母三元组和数字二元组向量:
转载地址:http://www.bianceng.cn/Programming/sjjg/201404/41066.htm
以上是用人的思维方式的解题过程,如果方法正确,加上运气好(三次假设都是正 确的,避免在错误分支上浪费时间),两分钟内就可得到结果。但是考虑到更通用的情况,字母数字 没有规律,也没有可供分析的入手点和线索,比如:
AAB – BBC = CCD
这样的问题,该什么方法解决呢?只能“猜想”,用穷举的方法试探每一种猜想,对每个 字母和数字穷举所有可能的组合,直到得到正确的结果。当然,这样的力气活交给计算机做是最合适 不过了。
1. 建立数学模型
要想让计算机解决问题,就要让计算机能够 理解题目,这就需要建立一个计算机能够识别、处理的数学模型,首先要解决的问题就是建立字母和 数字的映射关系的数学模型。本题的数学模型很简单,就是一个字母二元组:{char, number}。考察 等式:
WWWDOT - GOOGLE = DOTCOM
共出现了9个不同的字母:W、D、O、T、G、L、E、C 和M,因此,最终的解应该是9个字母对应的字母二元组向量:[ {'W', 7}, {'D', 5}, {'O', 8}, {'T', 9}, {'G', 1}, {'L', 0}, {'E', 3}, {'C', 4}, {'M', 6} ]。穷举算法就是对这个字母二元组向量中每个字母二元 组的number元素进行穷举,number的穷举范围就是0-9共10个数字,当然,根据题目要求,有一些字 符不能为0,比如W、G和D。排列组合问题的穷举多使用多重循环,看样子这个穷举算法应该是9重循环
了,在每层循环中对一个字母进行从0到9遍历。问题是,必须这样吗,对于更通用的情况,不是9个字 母的问题怎么办?首先思考一下是否每次都要遍历0-9。题目要求每个字母代表一个数字,而且不重 复,很显然,对每个字母进行的并不是排列,而是某种形式的组合,举个例子,就是如果W字母占用了 数字7,那么其它字母就肯定不是7,所以对D字母遍历是就可以跳过7。进一步,假设某次遍历的字母 二元组向量中除M字母外其它8个字母已经有对应的数字了,比如:
[ {'W', 7}, {'D', 5}, {'O', 8}, {'T', 9}, {'G', 1}, {'L', 0}, {'E', 3}, {'C', 4}, {'M', ?} ] (序列-1)
那么M的可选范围 就只有2和6,显然没必要使用9重循环。
现在换一种想法,对9个二元组的向量进行遍历,可以 分解为两个步骤,首先确定第一个二元组的值,然后对剩下的8个二元组进行遍历。显然这是一种递归 的思想(分治),算法很简单,但是要对10个数字的使用情况进行标识,对剩下的二元组进行遍历时 只使用没有占用标识的数字。因此还需要一个标识数字占用情况的数字二元组定义,这个二元组可以 这样定义:{number, using},0-9共有10个数字,因此需要维护一个长度为10的数字二元组向量。数 字二元组向量的初始值是:
[{0, false}, {1, false},{2, false},{3, false},{4, false}, {5, false},{6, false},{7, false},{8, false},{9, false}] (序列-2)
每进行一重递归 就有一个数字的using标志被置为true,当字母二元组向量得到(序列-1)的结果时,对应的数字二 元组向量的值应该是:
[{0, true}, {1, true},{2, false},{3, true},{4, true},{5, true},{6, false},{7, true},{8, true},{9, true}] (序列-3)
此时遍历这个数字二元组 向量就可以知道M字母的可选值只能是2或6。
穷举遍历的结束条件是每层递归中遍历完所有 using标志是false的数字,最外一层遍历完所有using标志是false的数字就结束了算法。
根据 题目要求,开始位置的数字不能是0,也就是W、G和D这三个字母不能是0,这是一个“剪枝”条件,要 利用起来,因此,对字母二元组进行扩充成字母三元组,添加一个leading标志:{char, number, leading}。下面就是这个数学模型的C语言定义:
4 typedef struct 5 { 6 char c; 7 int value; 8 bool leading; 9 }CharItem; 10 11 typedef struct 12 { 13 bool used; 14 int value; 15 }CharValue;
根据此数学模型初始化字母三元组和数字二元组向量:
29 30 CharItem char_item[max_char_count] = 31 { 32 { 'W', -1, true }, { 'D', -1, true }, { 'O', -1, false }, 33 { 'T', -1, false }, { 'G', -1, true }, { 'L', -1, false }, 34 { 'E', -1, false }, { 'C', -1, false }, { 'M', -1, false } 35 }; 36 37 CharValue char_val[max_number_count] = 38 { 39 {false, 0}, {false, 1}, {false, 2}, {false, 3}, 40 {false, 4}, {false, 5}, {false, 6}, {false, 7}, 41 {false, 8}, {false, 9} 42 }; 43
转载地址:http://www.bianceng.cn/Programming/sjjg/201404/41066.htm
相关文章推荐
- 移除百度地图LOGO和版权信息
- Category添加属性
- Leetcode Algorithm No.242 Valid Anagram
- 【Django】template中实现加减乘除数学运算[加法 减法 乘法 除法]
- oc中protocol、category和继承的区别
- oc中protocol、category和继承的区别
- 【Django】 终端打印出错信息
- 【Django】 密码加密
- 【Django】 国际化
- [译]Google新logo是如何缩减13000字节的
- 【Django】 上传图片
- uva 11090 Going in Cycle!! 平均权值最小的回路
- 15条谷歌轶事
- 【音乐分享】Let Me Go
- Google Chrome 快捷方式
- 【英语】Bingo口语笔记(71) - shit系列
- 【英语】Bingo口语笔记(70) - 最易忽略的2个连读技巧
- uva 11090 - Going in Cycle!!(二分+BellmanFord)
- vim如何配置go语言环境
- GoogleTest的使用01