Modest opinions  
by a humble autodidact
请回答下面10个问题,各题都恰有一个答案是正确的:
(1)第一个答案是B的问题是哪一个?
A、2      B、3      C、4      D、5        E、6

(2)恰好有两个连续问题的答案是一样的,它们是:
A、2,3      B、3,4      C、4,5      D、5,6      E、6,7

(3)本问题答案和哪一个问题的答案相同?
A、1      B、2      C、4      D、7     E、6

(4)答案是A的问题的个数是:
A、0       B、1       C、2       D、3     E、4

(5)本问题答案和哪一个问题的答案相同?
A、10     B、9       C、8        D、7     E、6

(6)答案是A的问题的个数和答案是什么的问题的个数相同?
A、B      B、C       C、D         D、E     E、以上都不是

(7)按照字母顺序,本问题的答案和下一个问题的答案相差几个字母?
A、4       B、3      C、2          D、1      E、0(注:A和B相差一个字母)

(8)答案是元音字母的问题的个数是:
A、2       B、3       C、4         D、5        E、6(注:A和E是元音字母)

(9)答案是辅音字母的问题的个数是:
A、一个质数       B、一个阶乘数       C、一个平方数       D、一个立方数       E、5的倍数

(10)本问题的答案是:
A、A       B、B         C、C        D、D        E、E

Ruby语言基于amb的解决方案,本质上,这是一个backtrack search:

# A B C D E
#
 0 1 2 3 4 
class ConstraintChecker
  
def initialize
    @constraints 
= [
     
# each constraint lambda expression should return false
     # if the corresponding answer(the "this_answer" param) 
     # is violated by answers seen so far(the "ans" param), 
     # and true if the answer is satisfied or can not be judged yet
     #~ lambda {|ans, this_answer| #test code
         #~ a = [1, 1, 2, 3, 1, 2, 3, 4, 3, 1]

         
#~ 0.upto(ans.length - 1) {|i|
           #~ break false if ans[i] && ans[i]!=a[i] 
         #~ } != false # true if break not executed
      #~ },
      #q1
      lambda {|ans, this_answer|
        firstB 
= [1,2,3,4,5][this_answer]
        ans[firstB] 
== nil or ans.index(1== firstB
      },
      
#q2
      lambda {|ans, this_answer|
        idx 
= [1,2,3,4,5][this_answer]
        
# ans[idx] is the same as ans[idx+1]
        0.upto(ans.size-2) {|i|
          
#~ puts "i=#{i}, idx=#{idx}, ans[i]=#{ans[i]}, ans[i+1]=#{ans[i+1]}"
          break true if ans[i+1== nil
          
break false if ((i==idx) != (ans[i]==ans[i+1]))
        } 
!= false
        
#~ ans[idx]==nil or ans[idx]==ans[idx-1]
      },
      
#q3
      lambda {|ans, this_answer|
        same 
= [0, 1365][this_answer]
        (ans[same] 
== nil) or (ans[same] == this_answer)
      },
      
#q4
      lambda {|ans, this_answer|
        numOfA 
= [0, 1245][this_answer]
        (ans.last 
== nil) or (ans.select{|i|i==0}.size == numOfA)
      },
      
#q5
      lambda {|ans, this_answer|
        same 
= [98765][this_answer]
        (ans[same] 
== nil) or (ans[same] == this_answer)
      },
      
#q6
      lambda {|ans, this_answer|
        
return true if ans.last == nil
        
#       A, B, C, D, E
        nums = [0, 0, 0, 0, 0]
        [0, 
1234].each do |i|
          ans.each do 
|j|
            nums[i] 
+= 1 if i==j
          end
        end
        
        idToA 
=[]
        
1.upto nums.size-1 do |i|
          idToA 
<< i if nums[i] == nums[0]
        end
        
        (idToA.empty? 
and this_answer == 4|| (idToA.size == 1 and idToA[0] == this_answer+1)
        
      },
      
#q7
      lambda {|ans, this_answer|
        nextAnswer 
= ans[7]  
        
return true if nextAnswer == nil
        [
4321, 0][this_answer] == (this_answer - nextAnswer).abs
      },
      
#q8
      lambda {|ans, this_answer|
        
return true if ans.last == nil
        ans.select{
|i| i==or i==4}.size == [2,3,4,5,6][this_answer]
      },
      
#q9
      lambda {|ans, this_answer|
        
return true if ans.last == nil
        numCon 
= ans.select{|i| i==1 or i==2 or i==3}.size
        
        conds 
= [[2357], [126], [149], [18], [0, 510]]
        conds.each_index do 
|i|
          
break false if (i == this_answer) != (conds[i].include? numCon)
        end 
!= false
      },
      
#q10
      lambda {|ans, this_answer|
        true
      }
    ]
  end
  
  
def Check(answers, upto=nil)
    
if (upto!=nil)  
      (upto
+1).upto answers.size-1 do |idx|
        answers[idx]
=nil
      end
    end
    
#~ print "Checking "; dump answers; puts
    answers.each_index do |i|
      
break unless answers[i] 
      
return false unless @constraints[i].call(answers, answers[i])
    end
  
    true
  end 
#of method Check
  
  
def num_constraint
    @constraints.size
  end
  
  
# exposion for debug purpose
  attr_reader :constraints
end 
#of class ConstraintChecker

class AmbSolver

  
def initialize
    @checker 
= ConstraintChecker.new
    @result 
= Array.new
  end
  
  
def solve
    require 
'amb'
    a 
= Amb.new
    begin
      answers = Array.new @checker.num_constraint
      answers.each_index do 
|i|
        next_answers 
= (0..4).to_a.collect{|n| answers[i]=n; answers.dup}
        answers 
= a.choose(*next_answers)
        a.
assert @checker.Check(answers)
      end
      @result 
<< answers.dup
      a.failure
    rescue Amb::ExhaustedError
    end
    @result
  end

end 
#of class AmbSolver

def dump answers
  answers.each do 
|a|
    (a
==nil)? print('?') : print(('A'..'Z').to_a[a])
    
print " "
  end
end

if __FILE__ == $0
  puts 
"Consistent answers:"
  start 
= Time.now
  result 
= AmbSolver.new.solve
  elapsed 
= Time.now - start
  result.each do 
|a|
    dump a
    puts
  end
  puts(
"time ", elapsed) #0.468
end
其中amb.rb库是Jim Weirich用continuation写出来的,我改动了一点:
# Modified Amb, originally by Jim Weirich
class Amb
    
class ExhaustedError < RuntimeError; end
    
    
def initialize
        @fail 
= proc { fail ExhaustedError, "amb tree exhausted" }
    end
    
    
def choose(*choices)
        prev_fail 
= @fail
        choices.each { 
|choice|
            callcc { 
|fk|
                @fail 
= proc {
                    @fail 
= prev_fail
                    fk.call(:fail)
                }
                
if choice.respond_to? :call
                    
return choice.call
                
else
                    
return choice
                 end
            }
        }
        @fail.call

    end
    
    
def failure
        choose
    end
    
    
def assert(cond)
        failure unless cond
    end
end


posted on 2008-04-14 19:48  yushih  阅读(466)  评论(1编辑  收藏  举报