手链样式
小明有3颗红珊瑚,4颗白珊瑚,5颗黄玛瑙。他想用它们串成一圈作为手链,送给女朋友。现在小明想知道:如果考虑手链可以随意转动或翻转,一共可以有多少不同的组合样式呢?
请你提交该整数。不要填写任何多余的内容或说明性的文字。
本文地址:http://blog.csdn.net/u013619254/article/details/50910788
这是2015年蓝桥杯省赛C++A组里面的一道题目,题目有点难理解,但搞清楚题意之后还是不难解决的。由于网上有几个版本的答案,而且都不对,所以现附上官方的答案:
(这是本人的老师参加蓝桥在厦大开的培训拿回来的资料):
首先来分析一下题目:3类珠子,一共12个,我们用字符串a="333444455555“表示,要求环形的排列数,注意理解可以随意转动或翻转,这跟直线型的有不同。举个例子:
例如,在直线型排列中a="333444455555“ 和 b="444455555333“ 是不同的排列,原因是直线型的起点是固定的,对应位置元素只要有一个不同,则排列不同。但是在环形里面,由于可以任意转动,也就是起点不固定的,当b以第一个3为起点时往右数时,它就和a完全一样了。另外,任意翻转的意思是b不但起点不固定,而且排列的方向可以往右数,也可以往左数。
因此,最暴力的解法来了:
1、用一个容器V保存不同样式的排列,首先将第一种排列保存起来,假设就保存a="333444455555“吧。
2、然后我们对"333444455555“进行全排列(排列的方法很关键等下会讲),每取出一个排列t,就和容器V里面的所有的样式Vi比较,比较方法:将两个t连在一起,形成tt,用C函数strstr判断Vi是否是tt的子字符串,如果是,则取下一个排列t1。反之,将tt翻转为tt‘,再用strstr判断Vi是否是tt ’的子字符串,如果不是,则t是一个新的样式,这时将t加入容器V中。
到此已经有解决问题的方法了,问题是如果采用纯递归的全排列方式,运行时间很久,具体多久我也不知道,反正我去饭堂吃了一顿饭回来还没运行出来。
12个数的全排列很大,但是我们应该注意到a="333444455555“有很多元素重复的,所以我们对其取全排列时应该去重,举个例子,122的全排列是122,122,221,221,212,212,,去重之后是122 ,212,221。要求去重全排列,可以自己在递归的基础上改,但是我们不用那么麻烦,直接调用函数next_permutation(A,A+size)就行了。该函数具体用法自行百度吧。注意的是需要将初始序列写成"333444455555“。
好了,说了那么多,还是直接上代码吧。如有问题,尽管提出。
#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <fstream>
#include <algorithm>
#include <vector>
#include <time.h>
using namespace std;
vector <string> C;//用一个vector保存已经产生的不同的样式
int num=1;
int main(){
// ifstream cin ("test.txt");
clock_t s,f;
s=clock();
char c[13]="333444455555";
C.push_back(c);//这肯定是一种排列
cout<<C[0];
do{
char tt[25],ttr[25];
strcpy(tt,c);//将一个c复制出来
strcat(tt,c);//tt是两个c连在一起
strcpy(ttr,tt);//备份一个ttr
strrev(ttr);//翻转ttr
char t1[13];
int f=1;
//cout<<tt<<" "<<ttr<<" "<<c<<endl;
for(int j=0;j<num;j++){//遍历保存好的样式C
for(int k=0;k<=12;k++){//for的目的是将C中的一个元素赋给t1,这样做的目的是因为直接用C[j],strstr函数用不了(⊙﹏⊙)b
t1[k]=C[j][k];
}
// cout<<t1<<endl;
if(strstr(tt,t1)||strstr(ttr,t1)){
f=0;
break; //有重复的则退出遍历C
}
}
if(f) {//没有有重复的
num++;
C.push_back(c);//将这个不同的排列加到C中
cout<<c<<" "<<num<<endl;
}
}while(next_permutation(c,c+12));
//调用stl里面的全排列函数,不要自己写递归全排列,因为本身要排列的序列有很多个元素相同的,会多很多无谓的尝试,浪费时间
f=clock();
cout<<endl<<"time "<<(f-s)/CLOCKS_PER_SEC<<endl;
return 0;
}