[从头学数学] 第36节 数学广角──推理

剧情提要:
[机器小伟]在[工程师阿伟]的陪同下进入练气期第四层功法的修炼,
这次要修炼的目标是[数学广角──推理]。

正剧开始:

星历2016年01月10日 14:45:20, 银河系厄尔斯星球中华帝国江南行省。
[工程师阿伟]正在和[机器小伟]一起研究[推理]这一节功法。

[从头学数学] 第36节 数学广角──推理_第1张图片



星历2016年01月10日 14:46:35, [工程师阿伟]说:这节功法中的问题,如果是由我来做
,当然是不费劲的,但是你做可要费大劲了。[机器小伟]。

小伟不相信。
14:47:46, 阿伟沉思了很久,最后决定还是让[机器小伟]来做这些题,尽管这样导致的是
难度系数会上几个层次,但阿伟想,要玩就玩得大点。

于是,阿伟为了让[机器小伟]做这些题,真正的发扬了愚公移山的精神。


来看上面这题吧:

<span style="font-size:18px;">def tmp():
    a = ['小红', '小丽', '小刚'];
    b = ['语文', '数学', '品德与生活'];
    
    result = [];
    for i in range(len(a)):
        for j in range(len(b)):
            result.append([a[i],b[j]]);

    for i in range(len(result)):
        for j in range(len(result)):
            for k in range(len(result)):
                if i == j or i == k or j == k:
                    continue;
                elif (result[i][0] != a[0] or result[i][1] != b[0]):
                    continue;
                elif (result[j][0] != a[1] or result[j][1] == b[1]):
                    continue;
                elif (result[k][0] != a[2]):
                    continue;
                elif (result[i][1] == result[j][1] or \
                      result[i][1] == result[k][1] or \
                      result[j][1] == result[k][1]):
                    continue;
                else:
                    print('{0} 拿的是 {1}, {2}拿的是{3}, {4}拿的是{5}'.format(\
                        result[i][0], result[i][1], \
                        result[j][0], result[j][1], \
                        result[k][0], result[k][1]));


                       
if __name__ == '__main__':
    tmp();

>>> 
小红 拿的是 语文, 小丽拿的是品德与生活, 小刚拿的是数学
>>> </span>



<span style="font-size:18px;">def tmp():
    a = ['欢欢', '乐乐', '笑笑'];
    b = [7, 5, 9];
    
    result = [];
    for i in range(len(a)):
        for j in range(len(b)):
            result.append([a[i],b[j]]);
    
    for i in range(len(result)):
        for j in range(len(result)):
            for k in range(len(result)):
                if  (result[i][0] == result[j][0] or \
                      result[i][0] == result[k][0] or \
                      result[j][0] == result[k][0]):
                    continue;
                elif (result[i][1] == result[j][1] or \
                      result[i][1] == result[k][1] or \
                      result[j][1] == result[k][1]):
                    continue;
                elif (result[i][0] != a[0] or \
                      result[j][0] != a[1] or \
                      result[k][0] != a[2]):
                    continue;
                elif (result[i][1] > result[j][1]):
                    continue;
                elif (result[k][1] > result[i][1] or \
                      result[k][1] > result[j][1]):
                    continue;
                else:
                    print('{0}重{1}千克, {2}重{3}千克, {4}重{5}千克'.format(\
                        result[i][0], result[i][1], \
                        result[j][0], result[j][1], \
                        result[k][0], result[k][1]));


                       
if __name__ == '__main__':
    tmp();

>>> 
欢欢重7千克, 乐乐重9千克, 笑笑重5千克</span>

[从头学数学] 第36节 数学广角──推理_第2张图片

<span style="font-size:18px;">def tmp():
    a = ['小冬', '小雨', '小伟'];
    b = ['一斑', '二斑', '三班'];
    
    result = [];
    for i in range(len(a)):
        for j in range(len(b)):
            result.append([a[i],b[j]]);
    
    for i in range(len(result)):
        for j in range(len(result)):
            for k in range(len(result)):
                if  (result[i][0] == result[j][0] or \
                      result[i][0] == result[k][0] or \
                      result[j][0] == result[k][0]):
                    continue;
                elif (result[i][1] == result[j][1] or \
                      result[i][1] == result[k][1] or \
                      result[j][1] == result[k][1]):
                    continue;
                elif (result[i][0] != a[0] or \
                      result[j][0] != a[1] or \
                      result[k][0] != a[2]):
                    continue;
                #各题判断条件的区别从这里开始
                elif (result[k][1] != b[2]):
                    continue;
                elif (result[j][1]== b[0]):
                    continue;
                else:
                    print('{0}在{1}, {2}在{3}, {4}在{5}'.format(\
                        result[i][0], result[i][1], \
                        result[j][0], result[j][1], \
                        result[k][0], result[k][1]));


                       
if __name__ == '__main__':
    tmp();
	
>>> 
小冬在一斑, 小雨在二斑, 小伟在三班
>>> </span>


这样的一种类型就全部突破了, 接着小伟看到了下面这种:

是数独吧,阿伟默默的想。
[从头学数学] 第36节 数学广角──推理_第3张图片


[从头学数学] 第36节 数学广角──推理_第4张图片

答案很简单,但得到答案的过程就不是那么简单了。阿伟不禁想起了所做的一切:

当初看到了这种题,阿伟首先想的是把所有的可能性放到一个候选集中,再从中选合适的,为此来做了一个求全排列的函数:


<span style="font-size:18px;">def perm(array):
    if (len(array)<=1):
        return [array];

    r = [];
    for i in range(len(array)):
        #抽去array[i]
        s = array[:i]+array[i+1:];
        p = perm(s);
        for x in p:
            #array[i]置顶
            r.append(array[i:i+1]+x);
    return r;


def tmp():
    array = [1,2,3,4];
    candidate = perm(array);
    print(candidate);
    print('共有{0}个候选者'.format(len(candidate)));</span>

然后,经过半天的奋战,阿伟郁闷地发现,用全排列会造成极度庞大的运算量,不可取。

经过再三的尝试,阿伟终于意识到,像这种题,要想单独让[机器小伟]去解决,那是不可能的,

其中回溯造成的运算量太庞大了,不可预知性太强了。最终,阿伟这样实现:

<span style="font-size:18px;">#测试有效性
def effective(num, matrix, row, col):
    span = len(matrix);

    for i in range(span):
        if matrix[i][col] == num:
            return 0;

    for j in range(span):
        if matrix[row][j] == num:
            return 0;

    return 1;

#测试结果是否成功
def success(matrix):
    for i in iter(matrix):
        if i == 0:
            return 0;

    return 1;</span>


<span style="font-size:18px;">def puzzle():
    span = 4;
    a = [[0]*span for i in range(span)];
    tryArray = [];
    tried  = [];

    a[0][0]=3;
    a[0][1]=2;
    a[1][3]=2;
    a[2][2]=3;
    a[3][0]=1;

    print('原矩阵是:');
    for i in range(span):
        print(a[i]);

    step = 0;
    gameover = 0;
    
    for row in range(span):
        if gameover == 1:
            break;
        for col in range(span):
            step+=1;
            if (a[row][col] == 0):
                tryArray = [];
                for num in range(1, span+1):
                    #数字num放在row, col处时和矩阵a不冲突就行
                    if effective(num, a, row, col):                    
                        tryArray.append(num);

                #考虑到让机器全程回溯不靠谱,实现为让机器给出选项,您来选择。
                if len(tryArray)>1:
                    print('第{0}步:现在的矩阵是:'.format(step));
                    for i in range(span):
                        print(a[i]);
                        
                    print('第{0}行, 第{1}列处的选择超过一个。有以下选择:'.\
                          format(row+1, col+1));
                       
                    for i in range(len(tryArray)):
                        print(tryArray[i], end=', ');
                    
                    a[row][col] = int(input('请输入您的选择:'));
                    tried.append(a[row][col]);
                elif len(tryArray)==1:
                    a[row][col] = tryArray[0];
                else:
                    print('\n\n前几步的选择造成无解的困境,请重新尝试,Game Over。');
                    print('您所做过的选择是:');
                    for i in range(len(tried)):
                        print(tried[i], end=', ');
                    gameover = 1;                    
                    
    if success(a, span, span):
        print('\n\n您成功了,您做了英明正确的选择,您所做的选择是:');
        for i in range(len(tried)):
            print(tried[i], end=', ');
        
        print('新矩阵是:');
        for i in range(span):
            print(a[i]);</span>


下面是阿伟和小伟共同完成的解答过程:
<span style="font-size:18px;">>>> 
原矩阵是:
[3, 2, 0, 0]
[0, 0, 0, 2]
[0, 0, 3, 0]
[1, 0, 0, 0]
第3步:现在的矩阵是:
[3, 2, 0, 0]
[0, 0, 0, 2]
[0, 0, 3, 0]
[1, 0, 0, 0]
第1行, 第3列处的选择超过一个。有以下选择:
1, 4, 请输入您的选择:4
第6步:现在的矩阵是:
[3, 2, 4, 1]
[4, 0, 0, 2]
[0, 0, 3, 0]
[1, 0, 0, 0]
第2行, 第2列处的选择超过一个。有以下选择:
1, 3, 请输入您的选择:3
第10步:现在的矩阵是:
[3, 2, 4, 1]
[4, 3, 1, 2]
[2, 0, 3, 0]
[1, 0, 0, 0]
第3行, 第2列处的选择超过一个。有以下选择:
1, 4, 请输入您的选择:1


您成功了,您做了英明正确的选择,您所做的选择是:
4, 3, 1, 新矩阵是:
[3, 2, 4, 1]
[4, 3, 1, 2]
[2, 1, 3, 4]
[1, 4, 2, 3]</span>

为了看起来更好看,阿伟又写了下面的函数来绘制矩阵:

<span style="font-size:18px;">/**
* @usage   绘制矩阵
* @author  mw
* @date    2016年01月10日  星期日  14:59:38 
* @param
* @return
*
*/
function drawMatrix(matrix, row, col) {
	plot.save();
	var digit = new Digit();
	var r = 30;
	
	for (var i = 0; i < row; i++) {
		for (var j = 0; j < col; j++) {
			plot.setStrokeStyle('black');
			digit.number(matrix[j][i], 2 * r * (i+1-2.5), 2 * r * (j+1-2.5), r);
			plot.setStrokeStyle('red');
			shape.strokeRect(2 * r * (i+1-2.5), 2 * r * (j+1-2.5), 2 * r, 2 * r);
		}
	}
	plot.restore();

}</span>


<span style="font-size:18px;">function myDraw() {
	var config = new PlotConfiguration();
	config.init();
	config.setPreference();
	config.setSector(1,1,1,1);
	
	var matrix = 
[[1, 3, 4, 2],
[2, 4, 3, 1],
[3, 2, 1, 4],
[4, 1, 2, 3]];
	
	
	drawMatrix(matrix, 4, 4);

}</span>


有了这些神器,后面的同类型问题就简单了:

[从头学数学] 第36节 数学广角──推理_第5张图片

[从头学数学] 第36节 数学广角──推理_第6张图片

<span style="font-size:18px;">    a[0][1]=3;
    a[1][3]=1;
    a[2][1]=2;
    a[3][0]=4;
    a[3][2]=2;


原矩阵是:
[0, 3, 0, 0]
[0, 0, 0, 1]
[0, 2, 0, 0]
[4, 0, 2, 0]
第1步:现在的矩阵是:
[0, 3, 0, 0]
[0, 0, 0, 1]
[0, 2, 0, 0]
[4, 0, 2, 0]
第1行, 第1列处的选择超过一个。有以下选择:
1, 2, 请输入您的选择:1
第5步:现在的矩阵是:
[1, 3, 4, 2]
[0, 0, 0, 1]
[0, 2, 0, 0]
[4, 0, 2, 0]
第2行, 第1列处的选择超过一个。有以下选择:
2, 3, 请输入您的选择:2


您成功了,您做了英明正确的选择,您所做的选择是:
1, 2, 新矩阵是:
[1, 3, 4, 2]
[2, 4, 3, 1]
[3, 2, 1, 4]
[4, 1, 2, 3]</span>

[从头学数学] 第36节 数学广角──推理_第7张图片

[从头学数学] 第36节 数学广角──推理_第8张图片

<span style="font-size:18px;">    a[0][0]=2;
    a[0][3]=3;
    a[2][1]=4;
    a[3][3]=2;
	
原矩阵是:
[2, 0, 0, 3]
[0, 0, 0, 0]
[0, 4, 0, 0]
[0, 0, 0, 2]
第5步:现在的矩阵是:
[2, 1, 4, 3]
[0, 0, 0, 0]
[0, 4, 0, 0]
[0, 0, 0, 2]
第2行, 第1列处的选择超过一个。有以下选择:
1, 3, 4, 请输入您的选择:1
第6步:现在的矩阵是:
[2, 1, 4, 3]
[1, 0, 0, 0]
[0, 4, 0, 0]
[0, 0, 0, 2]
第2行, 第2列处的选择超过一个。有以下选择:
2, 3, 请输入您的选择:2
第11步:现在的矩阵是:
[2, 1, 4, 3]
[1, 2, 3, 4]
[3, 4, 0, 0]
[0, 0, 0, 2]
第3行, 第3列处的选择超过一个。有以下选择:
1, 2, 请输入您的选择:2


您成功了,您做了英明正确的选择,您所做的选择是:
1, 2, 2, 新矩阵是:
[2, 1, 4, 3]
[1, 2, 3, 4]
[3, 4, 2, 1]
[4, 3, 1, 2]</span>

[从头学数学] 第36节 数学广角──推理_第9张图片


[从头学数学] 第36节 数学广角──推理_第10张图片

<span style="font-size:18px;">    a[0][2]=1;
    a[1][1]=2;
    a[1][3]=3;
    a[3][1]=3;


原矩阵是:
[0, 0, 1, 0]
[0, 2, 0, 3]
[0, 0, 0, 0]
[0, 3, 0, 0]
第1步:现在的矩阵是:
[0, 0, 1, 0]
[0, 2, 0, 3]
[0, 0, 0, 0]
[0, 3, 0, 0]
第1行, 第1列处的选择超过一个。有以下选择:
2, 3, 4, 请输入您的选择:3
第5步:现在的矩阵是:
[3, 4, 1, 2]
[0, 2, 0, 3]
[0, 0, 0, 0]
[0, 3, 0, 0]
第2行, 第1列处的选择超过一个。有以下选择:
1, 4, 请输入您的选择:1
第9步:现在的矩阵是:
[3, 4, 1, 2]
[1, 2, 4, 3]
[0, 0, 0, 0]
[0, 3, 0, 0]
第3行, 第1列处的选择超过一个。有以下选择:
2, 4, 请输入您的选择:2


您成功了,您做了英明正确的选择,您所做的选择是:
3, 1, 2, 新矩阵是:
[3, 4, 1, 2]
[1, 2, 4, 3]
[2, 1, 3, 4]
[4, 3, 2, 1]</span>

这一批题终于过去了,下面来了一种不同类型的题:



这种题就可以由[机器小伟]独自来做了:

<span style="font-size:18px;">def hasRepeat(array):
    size = len(array);
    for i in range(size):
        for j in range(i+1, size):
            if array[i] == array[j]:
                return 1;

    return 0;

def puzzle2():
    array = [];
    for a in range(1, 10):
        for b in range(1, 10):
            for c in range(1, 10):
                if (10*a + 7 + 10*b + c) == 58:
                    array=[5, 8, 7, a, b, c];
                    if hasRepeat(array) == 1:
                        pass;
                    else:
                        print('{0} + {1} = 58'.format(a*10+7, b*10+c));
                    array=[];         
					
>>> 
27 + 31 = 58
37 + 21 = 58</span>

<span style="font-size:18px;">def puzzle2():
    array = [];
    for a in range(1, 10):
        for b in range(1, 10):
            for c in range(1, 10):
                for d in range(1, 10):
                    if (10*a + b + 10*c + d) == 86:
                        array=[8, 6, a, b, c, d];
                        if hasRepeat(array) == 1:
                            pass;
                        else:
                            print('{0} + {1} = 86'.format(a*10+b, c*10+d));
                        array=[];           

>>> 
12 + 74 = 86
14 + 72 = 86
27 + 59 = 86
29 + 57 = 86
32 + 54 = 86
34 + 52 = 86
37 + 49 = 86
39 + 47 = 86
47 + 39 = 86
49 + 37 = 86
52 + 34 = 86
54 + 32 = 86
57 + 29 = 86
59 + 27 = 86
72 + 14 = 86
74 + 12 = 86

def puzzle2():
    array = [];
    for a in range(1, 10):
        for b in range(1, 10):
            for c in range(1, 10):
                for d in range(8,9):
                    if (10*a + b - (10*c + d)) == 74:
                        array=[7, 4, a, b, c, d];
                        if hasRepeat(array) == 1:
                            pass;
                        else:
                            print('{0} - {1} = 74'.format(a*10+b, c*10+d));
                        array=[];   

>>> 
92 - 18 = 74

def puzzle2():
    array = [];
    for a in range(1, 10):
        for b in range(2, 3):
            for c in range(1, 10):
                for d in range(1,10):
                    if (10*a + b - (10*c + d)) == 63:
                        array=[6, 3, a, b, c, d];
                        if hasRepeat(array) == 1:
                            pass;
                        else:
                            print('{0} - {1} = 63'.format(a*10+b, c*10+d));
                        array=[];   

>>> 
82 - 19 = 63</span>

很快,小伟就做完了。


接下来遇到的这种题好有趣:

[从头学数学] 第36节 数学广角──推理_第11张图片


答案是这样的:

[从头学数学] 第36节 数学广角──推理_第12张图片


为了得到这个答案,阿伟专门制作了神器来画这种排雷系的题:

<span style="font-size:18px;">function myDraw() {
	var config = new PlotConfiguration();
	config.init();
	config.setPreference();
	//config.setSector(1,1,1,1);
	//config.axis2D(0, 0, 180);
	
	var digit = new Digit();
	var r = 50;
	var row = 7;
	var col = 9;
	plot.translate(r, r);
	
	var array = new Array(row * col);
	for (var i = 0; i < row; i++) {
		for (var j = 0; j < col; j++) {
			array[i * col + j] = 0;
		}
	}
	
	//设置笑脸
	for (var x = 1; x < row; x+= 2) {
		for (var y = 1; y<col; y+=3) {

			array[x * col + y] = 'f';
		}
	}
	
	//计算数字
	for (var i = 0; i < row; i++) {
		for (var j = 0; j < col; j++) {
			if (array[i * col + j] == 'f') {
				if (i -1 >= 0) {
					if (j - 1 >= 0) {
						if (array[(i-1)*col + j-1] != 'f') 
							array[(i-1)*col + j-1]++;
					}
					
					if (j+1 < col) {
						if (array[(i-1)*col + j+1] != 'f') 
							array[(i-1)*col + j+1]++;
					}
					
					if (array[(i-1)*col + j] != 'f') 
						array[(i-1)*col+j]++;
				}
				
				if (i + 1 < row) {
					if (j - 1 >= 0) {
						if (array[(i+1)*col + j-1] != 'f') 
							array[(i+1)*col + j-1]++;
					}
					
					if (j+1 < col) {
						if (array[(i+1)*col + j+1] != 'f') 
							array[(i+1)*col + j+1]++;
					}
					
					if (array[(i+1)*col + j] != 'f') 
						array[(i+1)*col+j]++;
				}
				
				if (j - 1 >= 0) {
					if (array[i*col + j-1] != 'f') 
						array[i*col + j-1]++;
				}
				
				if (j+1 < col) {
					if (array[i*col + j+1] != 'f') 
						array[i*col + j+1]++;
				}
			}
		}
	}
				

	for (var i = 0; i < row; i++) {
		for (var j = 0; j < col; j++) {
			shape.strokeRect(j * r, i * r, r, r);
			if (array[i * col + j] == 'f') {
				plot.setFillStyle('red');
				shape.fillCircle(j * r, i * r, 20);
				plot.setFillStyle('yellow');
				shape.fillEllipse(j * r, i * r, 15, 10);

			}
			else if (array[i * col + j] > 0) {
				plot.setFillStyle('#880000');
				digit.number(array[i * col + j], j * r, i * r, r);
			}
		}
	}
	



}
</span>

上面这段代码可以得到下面这张图:

[从头学数学] 第36节 数学广角──推理_第13张图片


这种题要是依靠[机器小伟]做,想来也是太过艰难了,关键是阿伟现在功力消耗过大,已经

提不起精神再让小伟去做了,于是就自己解了答案,让小伟去验证:

<span style="font-size:18px;">/**
* @usage   找笑脸
* @author  mw
* @date    2016年01月10日  星期日  14:59:38 
* @param
* @return
*
*/
function myDraw_1() {
	var config = new PlotConfiguration();
	config.init();
	config.setPreference();
	//config.setSector(1,1,1,1);
	//config.axis2D(0, 0, 180);
	
	var digit = new Digit();
	var r = 50;
	var row = 7;
	var col = 9;
	plot.translate(r, r);
	
	var array = new Array(row * col);
	for (var i = 0; i < row; i++) {
		for (var j = 0; j < col; j++) {
			array[i * col + j] = 0;
		}
	}
	
	//设置笑脸
	var a = [0,2, 0,7, 1,5, 1,8, 3,2, 4,7];
	len = a.length / 2;
	
	for (var i = 0; i < len; i++) {
		array[a[2*i] * col + a[2*i+1]] = 'f';
	}

	
	//计算数字
	for (var i = 0; i < row; i++) {
		for (var j = 0; j < col; j++) {
			if (array[i * col + j] == 'f') {
				if (i -1 >= 0) {
					if (j - 1 >= 0) {
						if (array[(i-1)*col + j-1] != 'f') 
							array[(i-1)*col + j-1]++;
					}
					
					if (j+1 < col) {
						if (array[(i-1)*col + j+1] != 'f') 
							array[(i-1)*col + j+1]++;
					}
					
					if (array[(i-1)*col + j] != 'f') 
						array[(i-1)*col+j]++;
				}
				
				if (i + 1 < row) {
					if (j - 1 >= 0) {
						if (array[(i+1)*col + j-1] != 'f') 
							array[(i+1)*col + j-1]++;
					}
					
					if (j+1 < col) {
						if (array[(i+1)*col + j+1] != 'f') 
							array[(i+1)*col + j+1]++;
					}
					
					if (array[(i+1)*col + j] != 'f') 
						array[(i+1)*col+j]++;
				}
				
				if (j - 1 >= 0) {
					if (array[i*col + j-1] != 'f') 
						array[i*col + j-1]++;
				}
				
				if (j+1 < col) {
					if (array[i*col + j+1] != 'f') 
						array[i*col + j+1]++;
				}
			}
		}
	}
				

	for (var i = 0; i < row; i++) {
		for (var j = 0; j < col; j++) {
			shape.strokeRect(j * r, i * r, r, r);
			if (array[i * col + j] == 'f') {
				plot.setFillStyle('red');
				shape.fillCircle(j * r, i * r, 20);
				plot.setFillStyle('yellow');
				shape.fillEllipse(j * r, i * r, 15, 10);

			}
			else if (array[i * col + j] > 0) {
				plot.setFillStyle('#880000');
				digit.number(array[i * col + j], j * r, i * r, r);
			}
		}
	}
	



}</span>

笑脸全部在这里了。


这次玩得太High, 阿伟真是又痛又快乐。

本节到此结束,欲知后事如何,请看下回分解。



你可能感兴趣的:([从头学数学] 第36节 数学广角──推理)