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

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

我们知道圆排列就是在直排列后再除以排列的个数
那么我们先来看看直排列该怎么排列
首先,我们给3个红珊瑚进行排列,也就是C3 12, 然后再给4白珊瑚排列,也就是C4 9 最后剩下的5个空缺就留给黄玛瑙了
因为种类只有三种,所以我们在进行某一种珊瑚排序的时候,不需要考虑顺序。
所以直排的方案树是27720,但是我们进行的是圆排,所以我们还要除以12,结果为2310
在这里插入图片描述
上面我们已经解决了转动的问题,就是将直排所得方案数除以12
然后,我们来解决一下,翻转的问题。
我们想想一个环,他以y轴转动180后,他就对应了另一种排序方式,所以,我们可以想到,每一种排序方式都对应了一种旋转
180度后的排序,但是这两种方案在本题里面却是同一种情况。
所以我们给所有的方案数除以2,结果为1155
在这里插入图片描述
最后,我们不得不还要考虑一种情况,那就是对称,不同于旋转,对称的情况下,不旋转也是一样的。
所以,我们仅仅考虑对称情况下得方案总数
C1 5 乘上 C2 4 结果为 30
在这里插入图片描述

但是,我们要考虑一下了,第二步里面我们将所有得方案数都给除以了2,但是,实际情况却不是这样得,我们发现
在对称情况里,他们得每一种情况都是唯一得,不存在两种满足翻转180得情况
所得得是所有得对称得情况下得方案数。
最终得结果为,1155 + 30 / 2 = 1170
或者写为,(2310 - 30) / 2 + 30 = 1170

法二
用计算机编程思想

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

int main(){
    string s = "aaabbbbccccc";
    vector<string> v;
    
    int res = 0;
    do{
        int i = 0;
        for ( ;i < v.size(); i ++ ){
            if (v[i].find(s) != string::npos) break;//判断v里面是否含有当前字符串
        }
        
        if ( i < v.size()) continue;//如果i小于v.size()就说明vector里存在这个字符串了,就直接continue掉
        string ss = s + s;//可以给字符串去重
        
        v.push_back(ss);
        reverse(ss.begin(), ss.end());//将字符串翻转,考虑去除翻转的字符串
        v.push_back(ss);
        res ++;
    }
    while (next_permutation(s.begin(), s.end()));
    
    cout << res << endl;
    
    return 0;
}

为什么用S+S就可以给字符串去重
注意,在continue后,当时的res没有++,为什么可以看这里
全排列 next_permutation() 函数的用法
npos的用法

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值