2021.04.01手链样式
题目描述
小明有3颗红珊瑚,4颗白珊瑚,5颗黄玛瑙。
他想用它们串成一圈作为手链,送给女朋友。
现在小明想知道:如果考虑手链可以随意转动或翻转,一共可以有多少不同的组合样式呢?
思路
组合数学
- 如果不考虑环、不考虑翻转,则共有 t=(5+4+3)!5!∗4!∗3!t=\frac{(5+4+3)!}{5!*4!*3!}t=5!∗4!∗3!(5+4+3)!
- 如果考虑环,则有 t=t/12
- 如果考虑翻转
- 假设翻转后相同的有x个,则除去翻转前有t个,除去翻转后共有t−x2+x\frac{t-x}{2}+x2t−x+x个。
- 这里的翻转指的是将手链对折,由于红珊瑚和黄都是奇数个,所以在对折线上的必是红和黄,还剩RR WWWW YYYY,对于R WW YY共有5!2!∗2!=30\frac{5!}{2!*2!}=302!∗2!5!=30种不同排列。
所以答案为(5+4+3)!5!∗4!∗3!12−302−30=2170\frac{\frac{\frac{(5+4+3)!}{5!*4!*3!}}{12}-30}{2}-30 = 21702125!∗4!∗3!(5+4+3)!−30−30=2170
暴力
- 判断是否在转动后属于一种情况。
例子:
有字符串: a: “rwy” b: “wyr”,构造字符串 S = a+a: “rwyrwy”,如果b是S的子串,说明a和b转动属于一种情况。
- 判断是否在翻转后属于一种情况。
由于是沿着中心轴翻转,所以奇数个和偶数个元素情况是不同的,只考虑偶数个元素的情况。可以举例证得,翻转后的序列在转动后刚好是原序列的你序列。
所以,如果S在翻转后仍包含子序列b,说明a和b在翻转后属于一种情况。
代码
ArrayList<String> lis = new ArrayList<String>();
String s = "aaabbbbccccc";
boolean match(String a, String b) {
String S = a+a;
//考虑转动
if(S.indexOf(b)>0) return true;
//考虑翻转,即回文相等
StringBuffer sb = new StringBuffer();
for(int i = S.length()-1; i >= 0; i--) sb.append(S.charAt(i));
if(sb.toString().indexOf(b)>0) return true;
return false;
}
boolean has(String a) {
for(String s: lis) if(match(s, a)) return true;
return false;
}
void dfs(char[] a, int beg, int end) {
if(beg == end) {
String str = new String(a);
if(!has(str)) {
lis.add(str);
}
}
else {
for(int i = beg; i < end; i++) {
char t = a[i]; a[i] = a[beg]; a[beg] = t;
dfs(a, beg+1, end);
t = a[i]; a[i] = a[beg]; a[beg] = t;
}
}
}
void test3() {
dfs(s.toCharArray(), 0, s.length());
System.out.println(lis.size());
}
本文通过一个实例介绍了如何计算具有旋转和翻转因素的手链不同组合样式。利用组合数学和回文判断,解决奇数和偶数元素共存情况下的翻转问题。最后提供了一段代码实现,用于暴力枚举所有可能的组合。
3377

被折叠的 条评论
为什么被折叠?



