目录
回溯(2周)
项目 | 开始日期 | 结束日期 |
---|---|---|
二进制手表 | ||
八皇后 | 12.29 | 12.31 |
子集 | 1.1 | 1.1 |
有重复元素的子集 | 1.2 | 1.2 |
组合 | 1.2 | 1.2 |
排列 | 1.2 | 1.4 |
下一个排列(拓展) | 1.4 | 1.6 |
括号生成 | 1.6 | 1.8 |
数独 | 1.9 | 1.24 |
回溯模板
void backtrack(int leftnum,List<List> results,List currentState){
if(leftNum==0){
results.add(currentState);
}else{
for(所有的可能性){
做出选择
backtrack(leftnum-1,results,新的状态)
撤销选择
}
}
}
八皇后
直接套用回溯模板就可以,但是判断斜线上的皇后能否互相攻击有一定的技巧性,要注意到斜线上行+列数值相等,另外一个方向的斜线上行-列数值相等,可以用集合把行+列放入,这样可以快速判断能否攻击,不用再查找
子集
往结果集里面加入子集,要加入子集的深拷贝,不然你子集一变,结果集也变了,一定要注意当前处理的索引,从已经搜索过的状态的下一个状态开始搜索
排列
可以使用一个分区的思想,数组[0,index-1]是已经选过的排列,[index,N-1]是还没有排好的数,只要交换,就可以把某个数加入排列,这样比我以前用一个列表不断增加数到排序序列(见我以前的提交),然后查找这个列表某个数是不是已经加入了排列,要高效地多
括号生成
注意剪枝,不要硬搜,如果左括号数量不大于 nn,我们可以放一个左括号。如果右括号数量小于左括号的数量,我们可以放一个右括号。
数独
我之前的想法是每次找到解法最少的那个格子先填,所以我在初始化的时候先维护每个格子可以填的数的集合,然后在摆放格子的时候,比如你摆了1,那么同行同列同九宫格要去掉1,但是回溯的时候,你要撤销摆1就非常麻烦了,不能简单地把1加回到同行同列同九宫格,可能别人那个格子本来1是不可以填的,这样你又把1加上了,那么每个格子可以填的数的集合就没有得到正确的维护,而且所有格子都用差不多可能性的时候,并没有起到优化的作用
所以还是老老实实地按照老套路做,但是可以用数组记录下来同行同列同九宫格已经填过的数,这样查找起来会非常的快,如果某个数已经填过,就不要再填了