[回溯法] 和尚挑水问题-华为笔试
2016-10-20 16:19
337 查看
某寺庙里7个和尚:轮流挑水,为了和其他任务不能冲突,各人将有空天数列出如下表: 和尚1: 星期二,四; 和尚2: 星期一,六; 和尚3: 星期三,日; 和尚4: 星期五; 和尚5: 星期一,四,六; 和尚6: 星期二,五; 和尚7: 星期三,六,日; 请将所有合理的挑水时间安排表 。
输入为每个和尚从周一到周日的空闲情况,输出则为所有可能的任务安排表。
这道题用到了回溯法(backtracking),它的基本思想如下:
在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。 若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。 而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。
在本题中,每一种挑水策略为一个解,可从星期一开始,先选择一个空闲的和尚(如和尚1),接着到星期二再选一个和尚(空闲且非和尚1),接着依次类推直到星期日选完和尚,如果中途某天没有满足要求的和尚,则放弃该解。在每天选和尚时,都有(该天空闲和尚数-已挑过水的和尚数)种选择,通过穷举的方法,可以不断将解的范围扩大,直到遍历所有解。
下面给出具体代码:
#include <iostream> using namespace std; struct st { int isFree[7]; //和尚某天是否空闲(1为空闲) bool haveWorked; //在一次解法中是否挑过水(1为挑过水) }monk[7]; int sum; //方案总数 int x[7]={0}; //具体方案数组,1表示挑水,0表示不挑水 void backtrack(int n) { int i=0; if(n==7) //得到一组解并输出 { sum++; cout<<"第"<<sum<<"种方案:"<<endl; for(i=0;i<7;i++) cout<<x[i]<<' '; cout<<endl; } else { for(i=1;i<=7;++i) { if(monk[i-1].isFree ==1&&monk[i-1].haveWorked==false) //和尚i没有挑过水且在星期n有时间 { x =i; monk[i-1].haveWorked=true; backtrack(n+1); monk[i-1].haveWorked=false; } } } } int main() { int b[7][7]={{1,0,0,1,0,1,0},{0,0,1,1,0,0,0},{0,1,0,0,1,0,1},{1,1,0,0,0,1,0},\ {0,0,1,0,1,0,0},{0,0,0,1,0,0,1},{1,0,0,0,1,0,0}}; int i,j; for(i=0;i<7;++i) //状态初始化 { for(j=0;j<7;++j) monk[i].isFree[j]=b[i][j]; monk[i].haveWorked=false; } backtrack(0); return 0; }
相关文章推荐
- 华为和尚挑水问题(转化)
- 华为机试:和尚挑水问题
- 华为2016实习生招聘笔试题第三题--和尚挑水
- 华为上机笔试原题+代码---------股票投资问题
- 2013华为上机-装满篮子问题-回溯法
- 和尚挑水安排(回溯问题)
- 回溯法解决双核处理问题(某客某易笔试模拟题)
- (华为笔试)删数 约瑟夫环问题
- 和尚挑水问题
- [华为机试真题][2015]65.和尚挑水
- 2016华为暑期实习生编程题之和尚挑水
- p,v原语解决和尚挑水问题
- 常见Java问题答疑及笔试题(十六)——华为2016研发笔试
- 和尚挑水问题
- [华为机试真题][2015]65.和尚挑水
- 和尚挑水(回溯法)
- 华为上机笔试题目和代码—————语言识别问题
- 华为机试—N皇后问题(高级题160分:两种回溯法解决 吐血整理)
- 华为机试和尚挑水
- 华为笔试题:地铁换乘问题