标签:基本 描述 保存 思路 回溯 探索 scan size i++
一、dfs概括:
搜索与回溯(深度有限搜索)是用于未发现固定计算方式时,通过依次枚举各种情况,来求得最终结果的算法。
二、基本思路:
为了求得问题的解,先选择一种可能情况向前探索,在探索过程中,一旦发现原来的选择是错误的,说明前方已经无路可走,就退回一步重新选择。
这样继续向前探索,知道找到解或者证明无解为止。
三、算法框架:
(1)
int search(int k) { for(int i = 1;i <= 当前位置的情况数;i++) { if(满足条件) { 保存结果 if(到目的地) 输出解; else { search(k+1); } 恢复保存结果之前的状态(回溯一步); } } }
(2)
int search(int k) { if(到目的地) 输出解; else { for(int i = 1;i <= 当前位置的情况数;i++) { if(满足条件) { 保存结果 search(k+1); 恢复保存结果之前的状态(回溯一步); } } } }
ps:个人推荐使用第一种模版(至于原因。。。哎呀不要想这么多啦,看着顺眼就行)
四、例题:
(1)全排列问题:(洛谷P1706)
输出自然数 1到 n所有不重复的排列,即 n的全排列,要求所产生的任一数字序列中不允许出现重复的数字。
一个整数 n。
由 1 ~n 组成的所有不重复的数字序列,每行一个序列。
每个数字保留 5 个场宽
基本思路:
每次确定第i个数字应该放什么(可以放的标准是在当前序列中没有被使用过),确定以后,判断当前所有位置是否已被填满,
若已经被填满,则直接输出,若没有被填满,则继续向下搜索,判断第i+1位应该放的数字是什么.。
每输出一次,就把最后一位退掉(jud[i]归0),考虑下一种情况。
这么说到底是有点乱:
下面用实例模拟解释一下:
当n==3时
第一位先取1 进入第二位的选择,因为jud[1] = 1(被用过了),因此选2,再选第三位,因为jud[1] && jud[2] == 1(都被用过了),只能选3,
因此第一个序列为123
输出了,回溯一步,发现第三位还是只能选3,因此没有其他情况,再往前回溯一位,进行第二位的选择,此时可以取2、3,2在之前用过,
因此只能选3,选完后进入第三位的选择,只能选三,选完后发现位数x==3,因此输出,第二个序列为132
依次类推,得出所有答案。
上代码:
#include<cstdio> using namespace std; int n, ans[1004] = {}, jud[100004] = {}; void print()//输出函数,每次选满n为后输出当前选出的序列 { for(int i = 1;i <= n;i++) { printf(" %d", ans[i]); } printf("\n"); } void dfs(int x) { for(int i = 1;i <= n;i++)//用于枚举每一位上可能要选的数字(因为这里,所以在前面所有序列不变时,这个位置上不会被重复选择) { if(!jud[i])//这个数在之前没有被用过(在当前序列中没有被用过) { ans[x] = i;//没用过就可以选入当前序列 jud[i] = 1;//这个数被用过了,打上用过的标记 if(x == n)//选满了n位,输出 { print(); } else dfs(x+1);//如果没选满,就选下一位 jud[i] = 0;//所有操作都完成后,回溯一步,去掉i的标记 } } } int main() { scanf("%d", &n); dfs(1); return 0; }
标签:基本 描述 保存 思路 回溯 探索 scan size i++
原文地址:https://www.cnblogs.com/mint-hexagram/p/14819715.html