参考博客原址:https://blog.csdn.net/jinglelia/article/details/79344537
小明有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 ;
-
}