2021.04.01手链样式

2021.04.01手链样式

题目描述

小明有3颗红珊瑚,4颗白珊瑚,5颗黄玛瑙。
他想用它们串成一圈作为手链,送给女朋友。
现在小明想知道:如果考虑手链可以随意转动或翻转,一共可以有多少不同的组合样式呢?

思路

组合数学

  1. 如果不考虑环、不考虑翻转,则共有 t = ( 5 + 4 + 3 ) ! 5 ! ∗ 4 ! ∗ 3 ! t=\frac{(5+4+3)!}{5!*4!*3!} t=5!4!3!(5+4+3)!
  2. 如果考虑环,则有 t=t/12
  3. 如果考虑翻转
    1. 假设翻转后相同的有x个,则除去翻转前有t个,除去翻转后共有 t − x 2 + x \frac{t-x}{2}+x 2tx+x个。
    2. 这里的翻转指的是将手链对折,由于红珊瑚和黄都是奇数个,所以在对折线上的必是红和黄,还剩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)!3030=2170

暴力

  1. 判断是否在转动后属于一种情况。

例子:
有字符串: a: “rwy” b: “wyr”,构造字符串 S = a+a: “rwyrwy”,如果b是S的子串,说明a和b转动属于一种情况。

  1. 判断是否在翻转后属于一种情况。

由于是沿着中心轴翻转,所以奇数个和偶数个元素情况是不同的,只考虑偶数个元素的情况。可以举例证得,翻转后的序列在转动后刚好是原序列的你序列。

所以,如果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());
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值