zoukankan      html  css  js  c++  java
  • [算法] 高级搜索算法之迭代加深

    前言

    最开始搞 (OI) 的时候接触了搜索算法,后面基本上没有在练过了。若本文有误,请在讨论区指出。

    本文例题链接

    思想

    假设一张图, (ans1) 在很深的地方, (ans2) 离搜索树的根节点最近,但是需要找到的答案为 (ans3)

    首先考虑 (DFS) ,一般是一搜搜到底,很有可能找到 (ans1) 。若继续查找,很有可能花费太多时间。时间效率低。

    再来考虑 (BFS) ,它可以找到最近的答案 (ans2) 。若继续查找,很有可能存储状态的队列会浪费巨大空间。空间效率低

    现在引出 (IDDFS) ,它通常适用于有两个条件的问题:一是它是个最优解问题,二是最优的答案深度最小。且能够快速地找到答案。

    假设在搜索树中,每层树都有 (3) 个方案,即是搜索树为一颗 (3) 叉树,共 (2) 层, (ans)(3)

    在这里插入图片描述

    先来对比 (DFS) ,搜索路径为 (1-2-5-2-6-2-7-2-1-3) ,找到答案。有最坏情况,即每一个分支都是一个无底洞,若永远搜索不到答案,就会卡在里面。

    再来对比 (BFS) ,搜索路径为 (1-2-3) ,看起来比较短,但是队列中有 (1,2,5,6,7,3) 的信息,若答案更深一些,那么就会炸空间。

    通过上述两个例子,可以知道 (DFS)(BFS) 的局限性,但也各有千秋。结合两种算法,就有了迭代加深。首先限定一个层数,对于搜索树进行深度优先搜索。假设这个层数为 (1) ,那么深搜只会搜索到 (2) ,不会继续加深。首先试探性地来找答案,直到找到答案位置。很明显,上面几层的点会搜到很多遍,但时间复杂度对于 (DFS) 来说比较优,而在空间复杂度上比 (BFS) 上略胜一筹。

    很容易就写出模板:

    int max_depth = min_depth;
    Id_Dfs( int current_depth  ,  int max_depth ) {
    	if( current_depth > max_depth ) return ;
    	if( 找到答案 ){ 输出答案 ; (exit(0) ;  ||  return ;) }
    	for each ( 当前节点的儿子节点 )
    	Id_Dfs(current_depth + 1, max_depth) ;
    }
    for(; ; max_depth++ ) {
    	Id_Dfs( 0 , i ) ;
    }
    

    结合例题理解。

    题目

    一个与 (n) 有关的整数加成序列 (<a_0,a_1,a_2,...,a_m>) 满足以下四个条件:

    1. (a_0=1)
    2. (a_m=n)
    3. (a_0<a_1<a_2<...<a_{m-1}<a_m)
    4. 对于每一个 (k(1≤k≤m)) 都存在有两个整数 (i)(j(0≤i,j≤k-1)(i)(j) 可以相等 )) ,使得 (a_k=a_i+a_j)

    你的任务是:给定一个整数 (n) ,找出符合上述四个条件的长度最小的整数加成序列。如果有多个满足要求的答案,只需要输出任意一个解即可。

    思路

    按照 (1,2,4,8...) 这样来排列,找出最少需要的次数那么最少的层数就找到了,就减少了之前做的无用功。

    树上的子节点也较为好找,只需要将之前搜索到的数字,按照题意两两搭配找到下一项。

    只需要按照 (IDDFS) 的规则搜索就行了。但重点在于剪枝,写在注释里的。

    for(int i = nowdepth; i >= 1; i--) {
    	for(int j = nowdepth; j >= i; j--) {//两两搭配,且答案越大越容易找到解,故而到着找
    		if(ans[i] + ans[j] <= n && ans[i] + ans[j] > ans[nowdepth]) {//满足题意1,2两点的搜索
    			int now;//找到下一项
    			ans[nowdepth + 1] = now = ans[i] + ans[j];	
    			for(int k = nowdepth + 2; k <= limit; k++)
    //从nowdepth + 1这一项开始,后面最大时也就是now不停扩大2倍,若最大都达不到n,舍去不求
    				now <<= 1;
    			if(now < n)
    				continue;
    			Id_Dfs(nowdepth + 1);//搜索下一层
    			if(flag)//找到答案
    				return;
    		}
    	}
    }
    

    C++代码

    #include <cstdio>
    #include <cstring> 
    bool Quick_Read(int &N) {
    	N = 0;
    	int op = 1;
    	char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-')
    			op = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		N = (N << 1) + (N << 3) + (c ^ 48);
    		c = getchar();
    	}
    	N *= op;
    	return N != 0;
    }
    void Quick_Write(int N) {
    	if(N < 0) {
    		putchar('-');
    		N = -N;
    	}
    	if(N >= 10)
    		Quick_Write(N / 10);
    	putchar(N % 10 + 48);
    }
    const int MAXN = 1e5 + 5;
    int ans[MAXN];
    int limit;
    bool flag;
    int n;
    void Id_Dfs(int nowdepth) {
    	if(nowdepth > limit || flag)//达到层数不在恋战或找到答案,直接跳出
    		return;
    	if(ans[nowdepth] == n) {//满足题意
    		flag = true;
    		return;
    	}
    	for(int i = nowdepth; i >= 1; i--) {
    		for(int j = nowdepth; j >= i; j--) {//两两搭配,且答案越大越容易找到解,故而到着找
    			if(ans[i] + ans[j] <= n && ans[i] + ans[j] > ans[nowdepth]) {//满足题意1,2两点的搜索
    				int now;//找到下一项
    				ans[nowdepth + 1] = now = ans[i] + ans[j];	
    				for(int k = nowdepth + 2; k <= limit; k++)
    	//从nowdepth + 1这一项开始,后面最大时也就是now不停扩大2倍,若最大都达不到n,舍去不求
    					now <<= 1;
    				if(now < n)
    					continue;
    				Id_Dfs(nowdepth + 1);//搜索下一层
    				if(flag)//找到答案
    					return;
    			}
    		}
    	}
    }
    void Work() {
    	for(; !flag; limit++)//直到找到答案时停止搜索
    		Id_Dfs(1);
    	for(int i = 1; i < limit; i++) {//输出
    		Quick_Write(ans[i]);
    		putchar(' ');
    	}
    	putchar('
    ');
    }
    void Init() {
    	limit = 1;
    	int test = 1;
    	while(test < n) {//找到最小层数
    		test <<= 1;
    		limit++;
    	}
    	ans[1] = 1;
    	flag = false;
    }
    int main() {
    	while(Quick_Read(n)) {//多组输入输出,到0为止
    		Init();
    		Work();
    	}
    	return 0;
    }
    
  • 相关阅读:
    IOS调试下载的demo出现说项目不能在什么的SDK调试
    IOS手势基本用法
    IOS没有服务器断怎么调试Push代码
    VS Tips (Advance part)
    [转]如何理解C runtime library (C运行时库)
    Use AQTime to find the bottleneck of program module
    [转]Reflection: Discovery and Execution
    如何禁止生成stack对象或heap对象
    VS Tips (Basic part)
    栈对象、堆对象、静态对象的比较
  • 原文地址:https://www.cnblogs.com/C202202chenkelin/p/14373767.html
Copyright © 2011-2022 走看看