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 − x 2 + x \frac{t-x}{2}+x 2t−x+x个。
- 这里的翻转指的是将手链对折,由于红珊瑚和黄都是奇数个,所以在对折线上的必是红和黄,还剩RR WWWW YYYY,对于R WW YY共有 5 ! 2 ! ∗ 2 ! = 30 \frac{5!}{2!*2!}=30 2!∗2!5!=30种不同排列。
所以答案为 ( 5 + 4 + 3 ) ! 5 ! ∗ 4 ! ∗ 3 ! 12 − 30 2 − 30 = 2170 \frac{\frac{\frac{(5+4+3)!}{5!*4!*3!}}{12}-30}{2}-30 = 2170 2125!∗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());
}