题目描述:
小包最近发明了一种新的麻将,具体的规则如下:
总共有36张牌,每张牌是1~9。每个数字4张牌。
你手里有其中的14张牌,如果这14张牌满足如下条件,即算作和牌
14张牌中有2张相同数字的牌,称为雀头。
除去上述2张牌,剩下12张牌可以组成4个顺子或刻子。顺子的意思是递增的连续3个数字牌(例如234,567等),刻子的意思是相同数字的3个数字牌(例如111,777)
例如:
1 1 1 2 2 2 6 6 6 7 7 7 9 9 可以组成1,2,6,7的4个刻子和9的雀头,可以和牌
1 1 1 1 2 2 3 3 5 6 7 7 8 9 用1做雀头,组123,123,567,789的四个顺子,可以和牌
1 1 1 2 2 2 3 3 3 5 6 7 7 9 无论用1 2 3 7哪个做雀头,都无法组成和牌的条件。
现在,小包从36张牌中抽取了13张牌,他想知道在剩下的23张牌中,再取一张牌,取到哪几种数字牌可以和牌。
输入描述:
输入只有一行,包含13个数字,用空格分隔,每个数字在1~9之间
数据保证同种数字最多出现4次。
输出描述:
输出同样是一行,包含1个或以上的数字。代表他再取到哪些牌可以和牌。
若满足条件的有多种牌,请按从小到大的顺序输出。若没有满足条件的牌,请输出一个数字0
思路:
原理:如果该手牌胡牌,那么每个数字必然是,雀头、刻子、顺子的成员,
递归算法 : 从最小的数字开始尝试,如果把其当成雀头成员,该数字划掉两个,并看余下的数字能否划空
如果是刻子成员,该数字划掉三个,并查看余下数字能否划空
如果是顺子成员,划掉该值a, a + 1, a + 2,并查看余下数字能否划空
如果上述三种尝试都无法划空数组,说明存在数字无法是雀头、刻子、顺子的成员,
将一个数字牌补入13个牌之中,判断是否和牌,是则输出,不是则下一个数字牌
代码实现:
getNumFromString = lambda x:list(map(int,x.strip().split())) def isHePai(str): lenth = len(str) if lenth == 0: return True count1 = str.count(str[0]) # 第一个数字出现的次数 >= 2,且不是刻子,去掉雀头剩下的能不能和牌 if lenth%3!=0 and count1>=2 and isHePai(str[2:]): return True # 第一个数字是刻子,去掉刻子剩下的能不能和牌 if count1>=3 and isHePai(str[3:]): return True # 如果存在顺子,移除顺子后剩下的能和牌 if str[0]+1 in str and str[0]+2 in str: str1 = str[1:] str1.remove(str[0]+1) str1.remove(str[0]+2) if isHePai(str1): return True return False if __name__ == '__main__': a = getNumFromString(input()) flag = 0 for i in range(1,10): li = sorted(a+[i]) #这里要注意a+[i]与a.append(i)的区别(即a本身是否变化) if li.count(i)>4: continue else: # 判断 if isHePai(li): flag = 1 print(i,end=' ') # 若到了这步说明还没和牌 if flag == 0: print('0')
收获:
- 对于列表a,a+[x] 与 a.append(x) 是有区别的,前者a不变,后者a变了。
- 做递归时,第一步一定要设置终止条件。
- 做这类 若没有符合条件的则输出0的题目,可以设置一个标志位(flag)来进行区分。
昨天忙太晚了,没有更新题目,今天上午补上!