【Java/算法/组合】马路上有编号为1,2,3,4,......,10的十盏路灯,为省钱准备关掉其中的三盏,但又不能关掉相邻的两盏或三盏,而且两端的灯也不能关,求满足条件的关灯方案?
【数学解法】
位居首尾,编号为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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2022-04-27 【Oracle】更改Oracle用户的密码
2018-04-27 【Canvas与艺术】九角星
2018-04-27 【Canvas与艺术】环形双如意纹饰函数版
2018-04-27 【Python/crawl】如何使用Python爬虫将一系列网页上的同类图片下载到本地
2018-04-27 【Canvas与色彩】太空中看太阳
2014-04-27 实现淡入淡出效果的组件,继承自JComponent
2014-04-27 以JPanel为基础实现一个图像框