小明有3颗红珊瑚,4颗白珊瑚,5颗黄玛瑙。
他想用它们串成一圈作为手链,送给女朋友。
现在小明想知道:如果考虑手链可以随意转动或翻转,一共可以有多少不同的组合样式呢?
他想用它们串成一圈作为手链,送给女朋友。
现在小明想知道:如果考虑手链可以随意转动或翻转,一共可以有多少不同的组合样式呢?
分析:这个题首先一定要理解题意,转动和翻转是个什么意思,转动就是我们所得到的的排列是个环,即起点不固定,具体点说即使1234和2341是一种方式(3421也一样)。翻转就是,这个排列是个立体的,可以上下左右翻转,
具体点说即
1 1
2 3 和 3 2 是一样的(左右翻转),弄清了题意,就能事半功倍。
4 4
方法一:利用数学的排列组合进行求解,首先我们科普一个小的知识,见图:
意思很明白了,这个题,我们就是先C(12,3)选出红珊瑚的位置,在
C(9,5)选出黄马瑙的位置,这就是总的情况了,由于是环排列,我们将结果除以12,得到不考虑翻转的情况,然后再考虑翻转的时候要考虑到对称的情形,这种翻转是没有影响的,
对称即
A
A A
B B
B B
C C
C C
C
这种类型,这种情形的一共有C(5,2)*C(3,2) = 30种(只看一侧的),那么结果即:(2310-30)/2+30 = 1170;(立体排列除以2)
方法二:暴力枚举,我们直接把每一次得到的串先复制拼接一下(模拟旋转)成环,再翻转一下,如果两次得到的串在已得的串里面没有就加入,直接看代码吧,挺清楚的,鉴于c++里面有直接全排列去重的方法,那么我借鉴了,Java没有啊,直接写很麻烦。。。。
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
vector<string> v; //存储已经找出的情况
int sum = 0;
int main(){
string str = "aaabbbbccccc";
do{
vector<string>::iterator it;
for(it=v.begin(); it != v.end(); it++){
if((*it).find(str, 0) != string::npos){ //如果在已得的里面能找到,就判断下一个
break;
}
}
if( it != v.end() ) continue;
string str2 = str + str;
v.push_back(str2);
reverse(str2.begin(), str2.end()); //需要algorithm头文件
v.push_back(str2);
sum ++;
}while(next_permutation(str.begin(), str.end()));
cout << sum ;
}