题目描述
小明有3颗红珊瑚,4颗白珊瑚,5颗黄玛瑙。
他想用它们串成一圈作为手链,送给女朋友。
现在小明想知道:如果考虑手链可以随意转动或翻转,一共有多少不同的组合样式?
输出
请你输出该整数。不要输出任何多余的内容或说明性的文字。
首先一定要理解题意
转动和翻转是个什么意思,转动就是我们所得到的的排列是个环,即起点不固定,具体点说即使1234和2341是一种方式(3421也一样)。翻转就是,这个排列是个立体的,可以上下左右翻转
即
如何判断是否串是已经出现过的情况比较难想,下面提供一种思路
判断转动情况是否存在,可把字符串复制一份,查看其子串里是否含有某种字符串
如abcabc变为abcabcabcabc存起来
当要判断cabcab是否存在时,只需判断cabcab是否是abcabcabcabc的子串。
翻转用reverse函数翻转,再查看是否存在
注意翻转和转动可能同时存在,所以要把翻转传也要复制一份存起来。
注意翻转字符串一定不能直接翻转当前的串,因为当前传要完成全排列来模拟所有的情况,一旦翻转了串会认为已经变化了。所以翻转要翻转与其值相同的另外的串。
判断当前字符串是否已经存在使用的是vector,在每次插入新字符串之前要查重判断。判断函数 if(v[i].find(s) != string::npos)
string::npos如果作为一个返回值(return value)表示没有找到匹配项。
详细用法见string::npos的一些说明
代码如下
#include <iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<math.h>
#include<cmath>
#include<string>
using namespace std;
int main()
{
string s = "aaabbbbccccc";//模拟345三种宝石串
vector<string>v;
int ans = 0;
int quitflag;
do
{
quitflag = 1;
for(int i=0;i<v.size();i++)
{
if(v[i].find(s) != string::npos) //没到最后就找到了,说明有重复
{
quitflag = 0;
break;
}
}
if(quitflag == 0) continue;//如果找到重复的就跳过本次循环
string s2 = s+s;
v.push_back(s2);//两串相加用来判断转动
reverse(s2.begin(),s2.end());//翻转
v.push_back(s2);//翻转用来判断串翻转后相等的情况
ans++;
}while(next_permutation(s.begin(),s.end()));//全排列找出所有串的组合情况
cout<<ans;
}