【蓝桥杯训练】第四天1254

1254

[蓝桥杯2015初赛]手链样式

小明有3颗红珊瑚,4颗白珊瑚,5颗黄玛瑙。
他想用它们串成一圈作为手链,送给女朋友。
现在小明想知道:如果考虑手链可以随意转动或翻转,一共有多少不同的组合样式?
输出
请你输出该整数。不要输出任何多余的内容或说明性的文字。

注意

手链是可以转动翻转

算法

数学方法

  1. 首先要清楚这是一种环排列,并且是立体排列
  2. 用最原始的做法简化思考,当成一行排列:
    2.1 有12个珠子排列12!,但是跟相同珠子的相对位置没有关系,所以有12!/(5!4!3!)种
  3. 考虑环排列,环排列是因为相对位置无法确定,即需要一个参考。所以先拿一个占位,那么之前总数为 12!/(5!4!3!)/12 = 2310 种
  4. 考虑翻转:
    4.1 翻转必定要选一个为轴,干好红色和黄色为奇数,必定要1红1黄为轴。
    4.2 只看一边就是1红2白2黄的排列组合,如2.1一般 5!/(1!2!2!) = 30 种
    4.3 献出开翻转一样的,其他组合必有一对重复的。(2310-30)/2
  5. 最终数量应该是 30 + (2310-30)/2 = 1170
    有不足欢迎讨论。

暴力破解法

  1. 枚举暴力在当前这个数量还不算太大,12! = 479001600 = 4.7亿
  2. 转动即是123,231,312是一种,那利用字符串扩大一倍即可用寻找子串解决,即是123123中可以找到123,231,312
  3. 翻转将2的序列逆序即可321321

题解

说明:

  1. 利用了itertools.permutations产生全排列,他是一个生成器,每次返回的是一个元组,product可以产生笛卡尔积
  2. 利用了functools.reduce,将返回额元组合为字符串
#!/usr/bin/python3
import time
from itertools import permutations
from functools import reduce

def tupToString(tup):
    return reduce(f, tup)
    
start = time.time()
f = lambda a, b: a + b
chars = 'aaabbbbccccc'
sum = 0
v = []#存将要寻找的

for i in permutations(chars):
    SF = 0#找到了的标志量
    chars = tupToString(i) 
    for com in v:
        if chars in com:
            SF = 1
            break
    if SF:
        continue
    chars2 = chars + chars#可以任意转动
    v.append(chars2)
    chars2 = chars2[::-1]#可以翻转
    v.append(chars2)
    sum += 1
# print(v)
print(sum)
end = time.time()
print('runtime:{}s'.format(end-start))
posted @ 2020-01-20 11:18  燕山北  阅读(313)  评论(0编辑  收藏  举报