Chinaunix首页 | 论坛 | 博客
  • 博客访问: 22827
  • 博文数量: 17
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 12
  • 用 户 组: 普通用户
  • 注册时间: 2013-05-07 20:37
文章分类
文章存档

2014年(15)

2013年(2)

我的朋友

分类: IT业界

2014-04-22 10:16:14

     这本书,第三章讲到思维方法,比如:启发式的思考,根据结论隐藏的信息倒推。总结的很棒,我们解决问题就是用这么几种方法,包括逻辑和数学相关的所有问题。其中提到几个逻辑和编程的问题,我就顺便利用这些思维方法去思考题目的解。下面略举几例。

1.100根火柴两个人轮流取,每人每次只能取1~7根,拿到最后一根火柴赢,有必胜策略吗?
       我分析每人每次只能取1~7根,也就是我可以跟着对手后面凑数,两人每次取的根数区间是[2,14],要是我稳定的跟着对手,根据边界条件则只能选8。对手取1根时,我取7根,对手取7根,我取1根。12 * 8 = 96,也就是我可以跟12轮,还剩100 - 96 = 4根,要是我想赢,则必须开始时我先取4根。这是根据结论推倒的逆向思维过程,比仅仅知道解法有用。


2.两堆橘子,各为m和n个,两人轮流拿,拿的时候你只能选择某一堆在里面拿(即不能跨堆拿),你可以拿1~这堆里面所有剩下的橘子,谁拿到最后一个橘子谁赢。这个题目怎样能获胜?
       这个题目从最简单的情况开始思考,如果两堆各剩1个,那么后拿的人肯定赢;如果两堆各剩2个,那么先拿的人拿一个,后拿的人在另一堆拿一个,变成两堆各剩1个的情况,先拿的人拿两个,后拿的人拿另一堆的两个。
两堆各3个,各4个…… 先拿的人把一堆拿光,他会输,无论拿几个,后拿的人总可以把两边变的个数相等,最后总可以变成两堆各1个或者两堆各2个的情况。所以如果m != n,先拿的人把两堆拿成个数相等,就可以获胜。如果m == n,还是后拿吧,哈哈。


3.求最小(大)连续子序列。
       我想通过程序实现,遇到负数的时候,除非后面有正数能够大于这个,否则后面的连续数字序列就可以舍去。但我没办法预知一个负数后面跟一堆加起来没它大的数字,是否这个负数后面的数字会大于负数之前的数字,然后想到倒着遍历这个序列就可以了。
倒序遍历一堆正数,这些正数可能是最大连续子序列。遇到一个负数,如果负数和遍历过的所有正数相加结果是正数,则接着遍历;如果负数和遍历过的所有正数相加结果的负数,就说明从遍历开始到负数的子序列可以丢弃(正数的最大值留下,他们可能是最大连续子序列),再从负数下一个开始遍历就可以了。
代码如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: Yuande Liu

l = [36, -24, -75]
#l = [1, -2, 3]

def max_seq(l):
   total = 0 
   max_val = 0 

   for i, num in enumerate(reversed(l)):
       if num >= 0:
           total += num 
           max_val = max(total, max_val)

       elif total + num > 0:
           max_val = max(total, max_val)
           total += num 

       else:
           ret = max_seq( l[:len(l)-i-1] )
           max_val = max(ret, max_val)

   return max_val

def min_seq(l):
   return -max_seq( map(lambda x: -x, l) )

print max_seq(l)
print min_seq(l)

这里同时给出最小连续子序列。只要把序列取负值,然后调用最大连续子序列的函数,得到结果取负号。


希望这些例子能够启发大家的启发式思维,对倒推的思维逻辑有更好的理解。
阅读(318) | 评论(0) | 转发(0) |
0

上一篇:Linux中vi命令大全

下一篇:Shell之grep命令

给主人留下些什么吧!~~