程序员的算法趣题:Q30 用插线板制作章鱼脚状线路(Java版)

题目说明

对工程师而言,确保电源是最重要的事情。
不仅是 PC,当智能手机、平板电脑、数码相机等电量不足时,我们也肯定要四处寻找插座。
不过,多人共用的时候就必须共享插座,这时插线板就会派上用场。
一般的插线板除了有延长线,还会有多个插口。
这里假设有双插口和三插口的插线板。
墙壁上只有 1 个插座能用,而需要用电的电器有 n 台,试考虑此时应如何分配插线板。
举个例子,当 n = 4 时,如 图 21 所示,有 4 种插线板插线方法
(使用同一个插线板时,不考虑插口位置,只考虑插线板的连接方法。
另外,要使插线板上最后没有多余的插口)。

Q30 图21.png

求 n = 20 时,插线板的插线方法有多少种(不考虑电源的功率问题)?

思路

1.第一个插排有2孔或者3孔
2.如果第一个插排是2孔的,则两个分配方案进行组合
3.如果第一个插排是3孔的,则三个分配方案进行组合
4.定义一个递归方法f(n),返回值是留出n个孔的插排分配方式有多少种
5.比较特殊的是2孔或3孔中孔数相同的情况
(比如第一个插排是2孔插排,
   左孔的分配方案是留出3个孔:f(3),
   右孔的分配方案也是留出3个孔:f(3),
   此时需要排除重复的组合方式)。
   规律如下表所示,最终的公式已直接应用在代码中

单孔分配方案 f(i)2孔组合3孔组合
111
234
3610
41020
51535
n1+2+3+4+5+..+n(1+3+6+10+15+...n(n+1)/2)
nn(n+1)/2n(n+1)(n+2)/6

代码

public static void main(String[] args) {
    System.out.println(f(20)); // 63877262
}
/**
 * 留出n个孔的插排分配方式有多少种
 */
private static int f(int n){
    // 入参检查
    if(n <= 0) throw new IllegalArgumentException("入参不合法!n <= 0");

    if(n == 1) return 1;    // 留出1个孔,那就是空着,不放插排

    int count = 0;

    // 第一个插排是2孔插排
    for(int i = 1; i <= n / 2 ; i ++){
        int j = n - i;
        if(i == j){
            count += f(i) * (f(j)+1) / 2;       // 公式 n(n+1)/2
        }else{
            count += f(i) * f(j);
        }
    }

    // 第一个插排是3孔插排
    for(int i = 1; i <= n/3; i ++){             // 孔数i最少[1   ,   n/3 ]
        for(int j = i; j <= (n-i)/2; j ++){     // 孔数j居中[i   ,   (n-i)/2]
            int k = n - i - j;                  // 孔数k最大 n - i - j
            if(k <= 0) continue;

            if(i == j && j == k){
                count += ( f(i) * (f(j) + 1) * (f(k) + 2) ) / 6;    // 公式 n(n+1)(n+2)/6
            }else if(i == j){
                count += f(i) * (f(j) + 1) * f(k) / 2;
            }else if(j == k){
                count += f(i) * f(j) * (f(k) + 1) / 2;
            }else if(i == k){
                count += f(i) * f(j) * (f(k) + 1) / 2;
            }else{
                count += f(i) * f(j) * f(k);
            }
        }
    }

    return count;
}

结果

63877262

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值