【Java/算法/组合】马路上有编号为1,2,3,4,......,10的十盏路灯,为省钱准备关掉其中的三盏,但又不能关掉相邻的两盏或三盏,而且两端的灯也不能关,求满足条件的关灯方案?

文章介绍了如何解决一个数学问题,即在1到10编号的灯中关闭3盏,但不能关闭相邻或两端的灯。提供了数学组合和编程(Java)两种解法。数学解法利用组合公式排除连续关闭的情况,得到20种方案。编程解法通过创建组合器类进行8选3并过滤掉连续关闭的组合,最终同样得到20种符合条件的关灯方案。
摘要由CSDN通过智能技术生成

【数学解法】

位居首尾,编号为1和10的两盏灯是不能关的,这俩不考虑。

编号2-9的8盏灯关三盏,方案总数是C83,但这里有连续关闭的情况和题意抵触,再做下去不好做。

反过来想以下,把7盏打开的灯放好,把三盏关闭的灯往打开的灯中间插,就不存在连续的问题。

7盏灯外侧不能插,只能插在中间的六个空,这六个空就是三盏关闭的灯的插入位置。

6个空里选三个空插关闭的灯,方案是C63=6*5*4/3/2/1=20种。

【代码解法】

做一个从1到8的数组,用组合器进行8选三,以不连续为过滤条件去掉连续关闭的情况,剩下的就是符合条件的关灯方案。

主类Roadlamp代码:

package test230427;

import java.util.List;

import test230425.Combination;

/**
 * 马路上有编号为1,2,3,4,......,10的十盏路灯,为省钱准备关掉其中的三盏,但又不能关掉相邻的两盏或三盏,而且两端的灯也不能关,求满足条件的关灯方案?
 */
public class Roadlamp {
    public static void main(String[] args) {
        final int[] arr= {1,2,3,4,5,6,7,8};// 分别对应第2到第8盏灯
        Combination c=new Combination(arr,3);// 进行8选3
        List<List<Integer>> results=c.getResults();
        
        int idx=0;
        for(List<Integer> res:results) {
            // 过滤掉连续的灯
            boolean continuous=false;
            for(int i=0;i<res.size();i++) {
                for(int j=i+1;j<res.size();j++) {
                    if((res.get(i)+1)==res.get(j)) {
                        continuous=true;
                        break;
                    }
                }
            }
            
            if(continuous) {
                continue;
            }
            
            // 打开的灯
            String[] days= {"➀","➁","➂","➃","➄","➅","➆","➇","➈","➉"};
            // 关闭的灯
            String[] nights= {"➊","➋","➌","➍","➎","➏","➐","➑","➒","➓"};
            // 关掉三盏灯
            for(int i:res) {
                days[i]=nights[i];
            }
            
            System.out.println(String.format("%02d", ++idx) +"."+String.join(",", days));
        }
    }
}

辅助类Combination代码:

package test230425;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * 数学中排列组合中的组合器实现
 * 
 */
public class Combination {
    /**
     * 用于存放中间结果
     */
    private Stack<Integer> stack;
    
    /**
     * 用于存放结果
     */
    private List<List<Integer>> results;
    
    /**
     * 构造函数
     * @param arr 进行组合的元素
     * @param count 选多少个
     */
    public Combination(int[] arr,int count) {
        if(count>arr.length) {
            throw new ArrayIndexOutOfBoundsException(count+">"+arr.length);
        }
        
        stack = new Stack<>();
        results=new ArrayList<>();
        doSelect(arr,count,0,0);
    }
    
    /**
     * 进行选择
     * @param arr 目标数组
     * @param expect 期望选择数量
     * @param actual 实际选择数量
     * @param current 当前下标
     */
    private void doSelect(int[] arr, int expect, int actual, int current) {
        if(actual == expect) {
            List<Integer> list=new ArrayList<>();
            
            for(int i:stack) {
                list.add(i);
            }
            
            results.add(list);
            
            return;
        }
         
        for(int i=current;i<arr.length;i++) {
            if(!stack.contains(arr[i])) {
                stack.add(arr[i]);
                doSelect(arr, expect, actual+1, i);
                stack.pop();
            }
        }
    }
    
    /**
     * 取得组合结果
     * @return
     */
    public List<List<Integer>> getResults(){
        return results;
    }
    
    /**
     * 测试
     * @param args
     */
    public static void main(String[] args) {
        final int[] arr= {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30};
        final int count=2;
        
        Combination c=new Combination(arr,count);
        List<List<Integer>> results=c.getResults();
        
        int idx=0;
        for(List<Integer> res:results) {
            System.out.println(String.format("%02d", ++idx) +"."+res);
        }
    }
}

【运行结果即20种关灯方案】

01.➀,➋,➂,➍,➄,➏,➆,➇,➈,➉
02.➀,➋,➂,➍,➄,➅,➐,➇,➈,➉
03.➀,➋,➂,➍,➄,➅,➆,➑,➈,➉
04.➀,➋,➂,➍,➄,➅,➆,➇,➒,➉
05.➀,➋,➂,➃,➎,➅,➐,➇,➈,➉
06.➀,➋,➂,➃,➎,➅,➆,➑,➈,➉
07.➀,➋,➂,➃,➎,➅,➆,➇,➒,➉
08.➀,➋,➂,➃,➄,➏,➆,➑,➈,➉
09.➀,➋,➂,➃,➄,➏,➆,➇,➒,➉
10.➀,➋,➂,➃,➄,➅,➐,➇,➒,➉
11.➀,➁,➌,➃,➎,➅,➐,➇,➈,➉
12.➀,➁,➌,➃,➎,➅,➆,➑,➈,➉
13.➀,➁,➌,➃,➎,➅,➆,➇,➒,➉
14.➀,➁,➌,➃,➄,➏,➆,➑,➈,➉
15.➀,➁,➌,➃,➄,➏,➆,➇,➒,➉
16.➀,➁,➌,➃,➄,➅,➐,➇,➒,➉
17.➀,➁,➂,➍,➄,➏,➆,➑,➈,➉
18.➀,➁,➂,➍,➄,➏,➆,➇,➒,➉
19.➀,➁,➂,➍,➄,➅,➐,➇,➒,➉
20.➀,➁,➂,➃,➎,➅,➐,➇,➒,➉

数学解法和程序解法结果一致,可以相互印证。

END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值