代码之家  ›  专栏  ›  技术社区  ›  mafu

手上寻找街道和同类道路的算法

  •  12
  • mafu  · 技术社区  · 14 年前

    在麻将中,14个牌(牌就像扑克牌一样)被排列成4套1对。一条街道(“123”)总是使用3块瓷砖,不多也不少。同样的一组(“111”)也由3块瓷砖组成。这将得到3*4+2=14个瓷砖的总和。

    我在试着确定一只手是否可以按照上面描述的方式安排。出于某些原因,它不仅可以处理14块瓷砖,而且可以处理任意数量的瓷砖。(下一步是找出需要交换多少瓷砖才能完成一只手。)

    示例:

    11122233344455 -很简单,4套一双。
    12345555678999 -123456789555599
    11223378888999 -123,123,789,888,99号
    11223344556789

    我目前还没有实现的想法是:对于每一块瓷砖,试着制作a)一条街道b)一组c)一对。如果不起作用(或者将有一对),请返回上一个迭代并尝试下一个选项,或者,如果这是最高级别,则失败。否则,从剩余的平铺列表中删除已使用的平铺并继续下一个迭代。

    (不是家庭作业, I'm learning to play Mahjong. )

    3 回复  |  直到 7 年前
        1
  •  15
  •   Victor Nicollet    14 年前

    街道和集合中的值之和可以除以3:

    • n+n+n=3n

    所以,如果你把所有的数字加在一起,你会得到一个3N+2M形式的数字,其中M是两个平铺的值。除以3的余数( total % 3 )是,对于M的每个值:

    total % 3 = 0  -> M = {3,6,9}
    total % 3 = 1  -> M = {2,5,8}
    total % 3 = 2  -> M = {1,4,7}
    

    因此,不必测试九对可能的对,只需根据一个简单的加法尝试三对。对于每个可能的对,删除两个具有该值的平铺,然后转到算法的下一步以确定是否可能。

    一旦有了这个,就从最低的值开始。如果该值少于三个平铺,则表示它们一定是街道的第一个元素,因此删除该街道(如果由于缺少平铺n+1或n+2而无法删除,则表示手无效)并移到下一个最低值。

    如果至少有三个最小值的瓷砖,请将它们作为一组移除(如果您问“如果它们是街道的一部分,会怎样?”如果它们是,那么还有3个tile n+1和3个tile n+2,它们也可以变成一组)并继续。

    例如,对于无效手,总数是60,这意味着M={3,6,9}:

    Remove the 3: 112244556789
     - Start with 1: there are less than three, so remove a street
       -> impossible: 123 needs a 3
    
    Remove the 6: impossible, there is only one
    
    Remove the 9: impossible, there is only one
    

    以你的第二个例子 12345555678999

    Remove the 3: impossible, there is only one
    
    Remove the 6: impossible, there is only one
    
    Remove the 9: 123455556789
     - Start with 1: there is only one, so remove a street
       -> 455556789
     - Start with 4: there is only one, so remove a street
       -> 555789
     - Start with 5: there are three, so remove a set
       -> 789
     - Start with 7: there is only one, so remove a street
       -> empty : hand is valid, removals were [99] [123] [456] [555] [789]
    

    第三个例子11223378888999也有78个,这导致了回溯:

    Remove the 3: 11227888899
     - Start with 1: there are less than three, so remove a street
       -> impossible: 123 needs a 3
    
    Remove the 6: impossible, there are none
    
    Remove the 9: 112233788889
     - Start with 1: there are less than three, so remove streets
       -> 788889
     - Start with 7: there is only one, so remove a street
       -> 888
     - Start with 8: there are three, so remove a set
       -> empty, hand is valid, removals were : [99] [123] [123] [789] [888]
    
        2
  •  2
  •   Nikhil Freddroid    12 年前

    有一个特殊的情况,你需要做一些重新工作,以使它正确。这种情况发生在有一个运行三和一对具有相同的价值(但在不同的西装)。

    b2,b3,b4,b5,b6,b7,c4,c4,c4,d4,d4,d6,d7,d8
    
    d4,d4 should serve as the pair, and c4,c4,c4 should serve as the run-of-3 set.
    

    但由于3“c4”瓷砖出现在2 d4瓷砖之前,因此前2个c4瓷砖将作为一对拾取,留下一个孤立的c4和2 d4,而这3个瓷砖不会形成有效的集。

    在这种情况下,您需要将2个c4平铺“返回”到手(并保持手排序),然后搜索满足条件的下一个平铺(值==4)。要做到这一点,您需要让代码“记住”它已经尝试过c4,所以在下一次迭代中,它应该跳过c4并寻找值为=4的其他分片。代码会有点混乱,但可行。

        3
  •  1
  •   caveman    14 年前

    1. 找出可能的组合。我认为彻底检查这些数字是可行的。这个步骤的结果是一个组合列表,其中每个组合都有一个类型(集合、街道或对)和一个使用卡片的模式(可以是位图)。

    您还可以执行步骤1.5,检查每种类型的可用性是否足够。这一步和第二步将是您能够创建通用算法的地方。第一步将是相同的所有数量的瓷砖和可能的组合迅速。