寻找中文自描述句子

来源:互联网 发布:mac如何移动文件夹 编辑:程序博客网 时间:2024/05/17 07:55
 在字母语言里面自描述句子的例子( see http://hi.baidu.com/mynana/blog/item/bfb3aeafa707a1cc7dd92a04.html):
       "Only the fool would take trouble to verify that this sentence was composed of ten a's, three b's, four c's, four d's, forty-six e's, sixteen f's, four g's, thirteen h's, fifteen i's, two k's, nine l's, four m's, twenty-five n's, twenty-four o's. five p's, sixteen r's, forty-one s's, thirty-seven t's, ten u's, eight v's, eight w's, four x's, eleven y's, twenty-seven commas, twenty-three apostrophes, seven hyphens and, last but not least, a single !"
    句子的主体说明了字母的个数。
    我想到的是要找到‘中文’自描述句子,因为没有字母,所以用笔画取代,形如:
        "本个句子有一十二个一划字一十三个二划字一十九个三划字一十个四划字一十七个五划字七个六划字"
    注意这个句子只是样例,真正是否存在还是未知的.
    采用了一种搜索方法:从一个状态开始,对任意一个笔划作校正,如果碰到重复的句子就让全部笔划随机跳到另外一个状态.
    这是昨天的思路,有两个有意思的运行现象:
    1) 因为采用了python的dict做hash), key是中文的数字,unicode,比较消耗内存, ubuntu已经到了90%的内存+1个G的swap,到后来cpu什么都不干了,光作磁盘swap来回查hash; 后来还是死机了...
    2) 随机算法到最后会有非常少的遗漏状态空间,来回跳,如果要遍历完会花很长时间

    针对第一个做了调整,优化了hash存储,用阿拉伯数字作key;对第二个就是在剩余空间小于一个值后,直接上蛮力搜索.
    现在能够搜索完整了,但是又发现第三个现象:
    3) 不是每个句子都可能构造出的
    比如上面那句就不行,但是这个句子就可以,尽管不太通顺,因为有两个‘个’字:
       "本个个句子有二个一划字六个二划字一十个三划字三个四划字九个五划字七个六划字"
    没关系,只是实验而言,剩下的任务就是构造通顺的句子了, 基本上就是随便加一些或者改一些就好, 第一个中文自描述句子诞生了!:  
    ==================================================   
   "这个句子有二个一划字九个二划字九个三划字二个四划字九个五划字八个六划字一个七划字"
    ===================================================

代码如下:
   
  1. #-*- coding: UTF-8 -*-
  2. import random
  3. import operator
  4. def get_cnt( s, i ):
  5.     res = 0
  6.     for c in s:
  7.         j = word_cnt[ c ]
  8.         if j == i:
  9.             res += 1
  10.     return res
  11. def stat( s ):
  12.     global word_cnt
  13.     cnts = [ 0 ] * 7
  14.     for c in s:
  15.         cnts[ word_cnt[ c ] - 1 ] += 1
  16.     return cnts    
  17. def convert_num_to_chinese( i ):
  18.     ''''' assume i < 100 '''
  19.     global chinese_nums
  20.     first, second = divmod( i, 10 ) 
  21.     s = ""
  22.     if first != 0:
  23.         s += "".join( ( chinese_nums[ first ],  u"十" ) )
  24.     if second != 0:
  25.         s += chinese_nums[ second ]
  26.     return s    
  27. def convert_chines_to_num( s ):
  28.     ''''' assume s < 100 '''
  29.     if len( s ) == 1:
  30.         return nums_chinese[ s ]
  31.     else:
  32.         num = 0
  33.         first, second = s.split( u'十' )
  34.         if first:
  35.             num += nums_chinese[ first ] * 10
  36.         if second:
  37.             num += nums_chinese[ second ] 
  38.         return num    
  39. def combine_sentence():
  40.     global prefix, postfixes, chinese_cnts 
  41.     return prefix + "".join( map( operator.add,  chinese_cnts, postfixes ) )
  42.     
  43. chinese_nums = dict( zip( range( 110), u'一二三四五六七八九' ) ) 
  44. nums_chinese = dict( zip(  u'一二三四五六七八九十' , range( 111) ) ) 
  45. word_cnt = dict( zip( (u'这本个句子有划字一二三四五六七八九十'), 
  46.                       (7,5,3,5,2,6,6,5,1,2,3,5,4,4,2,2,2,2) )
  47.                ) 
  48. prefix = u'这个句子有' 
  49. postfixes = [ u'个一划字', u'个二划字', u'个三划字',  u'个四划字', u'个五划字', u'个六划字', u'个七划字']
  50. init_cnts = stat(  prefix + "".join( postfixes ) ) 
  51. chinese_cnts = map( convert_num_to_chinese, init_cnts )
  52. print ",".join( chinese_cnts )
  53. print convert_chines_to_num( u'二十一')
  54. print convert_chines_to_num( u'十一')
  55. print convert_chines_to_num( u'二十')
  56. print convert_chines_to_num( u'二')
  57. #print stat( u'本个个句子有二个一划字六个二划字一十个三划字三个四划字九个五划字七个六划字' ) 
  58. #s = u'这个句子有二个一划字九个二划字九个三划字二个四划字九个五划字八个六划字一个七划字' 
  59. #print stat( s )
  60. #print "".join( sorted( s, cmp = lambda x,y: cmp( word_cnt[x], word_cnt[y]) ) )
  61. #import sys; sys.exit()
  62. MaxRange = 12
  63. EndSize = MaxRange ** 5 * 99 / 100
  64. found = 0
  65. history = {}
  66. while not found:
  67.     sentence = combine_sentence()
  68.     print sentence
  69.     print '-' * 50
  70.     print len( history ) 
  71.     key = " ".join( map( lambda x: str( convert_chines_to_num(x) ),  chinese_cnts ) ) 
  72.     if history.has_key( key ):
  73.         cnts = [ random.randint( 0, MaxRange ) for i in range(5) ]
  74.         cnts = map( operator.add, cnts, init_cnts[:5] )
  75.         chinese_cnts = map( convert_num_to_chinese, cnts ) +  chinese_cnts[5:] 
  76.         print 'same, jump to ', cnts
  77.         continue
  78.     history[ key ] = 1 
  79.     cnts = stat( sentence )
  80.     real_cnts = map( convert_num_to_chinese, cnts )
  81.     print ",".join( real_cnts )
  82.     print ",".join( chinese_cnts )
  83.     
  84.     if chinese_cnts == real_cnts: 
  85.         found = 1
  86.         print 'found'
  87.     else:    
  88.         # no need to change six, for no six in chinese number
  89.         i = random.choice( range(05 ) ) 
  90.         cnt = get_cnt( sentence, i + 1 )     
  91.         chinese_cnts[ i ] = convert_num_to_chinese( cnt )
  92.     if len( history ) > EndSize:
  93.         break
  94. #traverse instead of random choose 
  95. if not found:
  96.     for s1 in range(0, MaxRange ):
  97.         for s2 in range(0, MaxRange ):
  98.             for s3 in range(0, MaxRange ):
  99.                 for s4 in range(0, MaxRange ):
  100.                     for s5 in range(0, MaxRange ):
  101.                         cnts = [ s1, s2, s3, s4, s5 ]
  102.                         cnts = map( operator.add, cnts, init_cnts[:5] )
  103.                         chinese_cnts = map( convert_num_to_chinese, cnts ) + chinese_cnts[5:] 
  104.                         key = " ".join( map( lambda x: str( convert_chines_to_num(x) ),  chinese_cnts ) ) 
  105.                         if not history.has_key( key ):
  106.                             sentence = combine_sentence()
  107.                             cnts = stat( sentence )
  108.                             real_cnts = map( convert_num_to_chinese, cnts )
  109.                             if chinese_cnts == real_cnts: 
  110.                                 found = 1
  111.                                 print 'found'
  112.                             print sentence
  113. if not found:
  114.     print 'impossible'
  115.     
  116.     
  117.     

原创粉丝点击