手链样式

手链样式

小明有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;
}







  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值