`

搜索(一)——剪枝

 
阅读更多

参考文档:《搜索方法中的剪枝优化》——南开中学 齐鑫(见附件《剪枝》)

 

 

一、剪枝优化的核心问题是设计剪枝判断方法,即确定哪些枝条应当舍弃,哪些枝条应当保留的方法。

 

二、剪枝的原则:

1. 正确性:

必须保证不丢失正确的结果 ,这是剪枝优化的前提。
为了满足这个原则,我们就应当利用“必要条件”来进行剪枝判断。也就是说,通过解所必须具备的特征、必须满足的条件等方面来考察待判断的枝条能否被剪枝。这样,就可以保证所剪掉的枝条一定不是正解所在的枝条。当然,由必要条件的定义,我们知道,没有被剪枝不意味着一定可以得到正解(否则,也就不必搜索了)。

 

2. 准确性:尽多剪枝

能够尽可能多的剪去不能通向正解的枝条

 

3. 高效性:权衡“剪枝判断开销”和“剪枝提速效果”

剪枝判断的副作用及其改善:[ 一般说来,设计好剪枝判断方法之后,我们对搜索树的每个枝条都要执行一次判断操作。然而,由于是利用出解的“必要条件”进行判断,所以,必然有很多不含正解的枝条没有被剪枝。这些情况下的剪枝判断操作,对于程序的效率的提高无疑是具有副作用的。为了尽量减少剪枝判断的副作用,我们除了要下功夫改善判断的准确性外,经常还需要提高判断操作本身的时间效率。]
然而这就带来了一个矛盾 :我们为了加强优化的效果,就必须提高剪枝判断的准确性,因此,常常不得不提高判断操作的复杂度,也就同时降低了剪枝判断的时间效率;但是,如果剪枝判断的时间消耗过多,就有可能减小、甚至完全抵消提高判断准确性所能带来的优化效果,这恐怕也是得不偿失。很多情况下,能否较好的解决这个矛盾,往往成为搜索算法优化的关键。

 

三、可行性剪枝

在很多情况下,并不是搜索树中的所有枝条都能通向我们需要的结果,很多的枝条实际上只是一些死胡同。如果我们能够在刚刚进入这样的死胡同的时候,就能够判断出来并立即剪枝

 

四、最优性剪枝 /上下界剪枝

在我们平时遇到的问题中,有一大类是所谓最优化问题,即所要求的结果是最优解。如果我们使用搜索方法来解决这类问题,那么,最优性剪枝是一定要考虑到的。
为了表述的统一,首先要作一些说明:我们知道,解的优劣一般是通过一个评价函数来评判的。这里定义一个抽象的评价函数——“优度”,它的值越大,对应的解也就越优(对于具体的问题,我们可以认为“优度”代表正的收益或负的代价等)。
然后,我们再来回顾一下搜索最优解的过程:一般情况下,我们需要保存一个“当前最优解”,实际上就是保存解的优度的一个下界。在遍历到搜索树的叶子节点的时候,我们就能得到一个新的解,当然也就得到了它的评价函数值,与保存的优度的下界作比较,如果新解的优度值更大,则这个优度值就成为新的下界。搜索结束后,所保存的解就是最优解。
那么,最优性剪枝又是如何进行的呢?当我们处在搜索树的枝条上时,可以通过某种方法估算出该枝条上的所有解的评价函数的上界,即所谓估价函数 。显然, 大于当前保存的优度的下界,是该枝条上存在最优解的必要条件,否则就一定可以剪枝。所以,最优性剪枝也可以称为“上下界剪枝”。同时,我们也可以看到,最优性剪枝的核心问题就是估价函数的建立。

 

例题:

 

1. POJ 2331 Water Pipe==> IDA* +剪枝

    语法注意:一般在使用memset()时,都不要将memset()放到子程序中初始化一个指针参数对应数组,直接在外面memset()就好了。避免出错! 参见“分类C/C++” ==> “指针常量,指针变量(sizeof使用注意)”

 

# include <cstdio>
# include <cstring>
# include <queue>
using namespace std;

int x1,y1,x2,y2;
int k;
int l[5];
int c[5];

int cmin;

//(A*启发函数) h[i][j]是在假设有无限多每种型号的管道时,从(i,j)到目的点(x2,y2)至少还需要多少根管道
int hx[1001];
int hy[1001];

void bfs(int *h, int endPos){
	queue<int> q;

	h[endPos]=0;
	q.push(endPos);

	int curPos;
	while(!q.empty()){
		curPos=q.front();
		q.pop();

		int i;//假设每种型号的管道取之不尽
		for(i=0;i<k;i++){
			if(curPos-l[i]>=1 && h[curPos-l[i]]==-1){
				h[curPos-l[i]]=h[curPos]+1;
				q.push(curPos-l[i]);
			}
			if(curPos+l[i]<=1000 && h[curPos+l[i]]==-1){
				h[curPos+l[i]]=h[curPos]+1;
				q.push(curPos+l[i]);
			}
		}
	}
}
bool dfs(int cur, int depth, int type){
	if(type==0){
	//剪枝
	if(depth+hx[cur]>cmin || hx[cur]==-1)
		return false;
	
	//x深搜到值后,继续深搜y
	if(cur==x2){
		return dfs(y1,depth,1); //注意:不是dfs_y(y1,depth+1)
	}


	int i;
	for(i=0;i<k;i++){
		if(c[i]==0) continue;

		if(cur<x2){
			if(cur+l[i]<=1000){ // 不要反复检查: && hx[curX+l[i]]!=-1){
				c[i]--;
				if(dfs(cur+l[i],depth+1,0))
					return true;
				c[i]++;
			}
			if(cur-l[i]>=1){
				c[i]--;
				if(dfs(cur-l[i],depth+1,0))
					return true;
				c[i]++;
			}
		}else{
			if(cur-l[i]>=1){
				c[i]--;
				if(dfs(cur-l[i],depth+1,0))
					return true;
				c[i]++;
			}
			if(cur+l[i]<=1000){
				c[i]--;
				if(dfs(cur+l[i],depth+1,0))
					return true;
				c[i]++;
			}
		}	
	}

	}else{
	//剪枝
	if(depth+hy[cur]>cmin || hy[cur]==-1)
		return false;

	//y深搜到值
	if(cur==y2){
		return true;
	}

	int i;
	for(i=0;i<k;i++){
		if(c[i]==0) continue;
		//根据大致方向优先向某个方向扩展
		if(cur<y2){
			if(cur+l[i]<=1000){
				c[i]--;
				if(dfs(cur+l[i],depth+1,1))
					return true;
				c[i]++;
			}
			if(cur-l[i]>=1){
				c[i]--;
				if(dfs(cur-l[i],depth+1,1))
					return true;
				c[i]++;
			}
		}else{
			if(cur-l[i]>=1){
				c[i]--;
				if(dfs(cur-l[i],depth+1,1))
					return true;
				c[i]++;
			}
			if(cur+l[i]<=1000){
				c[i]--;
				if(dfs(cur+l[i],depth+1,1))
					return true;
				c[i]++;
			}
		}
		
	}
	}
	return false;
}

int main(void){
	scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k);
	int i,depth_max=0;
	for(i=0;i<k;i++)
		scanf("%d",&l[i]);
	for(i=0;i<k;i++){
		scanf("%d",&c[i]);
		depth_max+=c[i];
	}

	//计算A*启发函数
	memset(hx,-1,sizeof(hx));
	memset(hy,-1,sizeof(hy));
	bfs(hx,x2);
	bfs(hy,y2);

	//迭代加深DFS
	for(cmin=0;cmin<=depth_max;cmin++){//保证cmin在循环内部不被修改
		if(dfs(x1,0,0)) break;
	}

	if(cmin<=depth_max)
		printf("%d",cmin);
	else
		printf("%d",-1);

	return 0;
}
 

 

 

 

 

分享到:
评论

相关推荐

    ACM回溯法中的搜索剪枝

    ACM中的回溯法:搜索是人工智能中的一种基本方法,也是信息学竞赛选手所必须熟练掌握的一种方法。我们在建立一个搜索算法的...本文所讨论的主要内容就是在建立算法的结构之后,对程序进行优化的一种基本方法——剪枝。

    人工智能第二次大作业——αβ剪枝五子棋.zip

    本篇将围绕“人工智能第二次大作业——αβ剪枝五子棋”这一主题,深入探讨如何利用AI技术,特别是αβ剪枝算法,来实现一个五子棋游戏的智能对手。 五子棋是一种策略性棋类游戏,对弈双方轮流在棋盘上下棋,先连成...

    Alphaαβ剪枝算法 实现井字棋人工智能作业

    本文将聚焦于一个经典的游戏——井字棋(Tic Tac Toe),探讨如何通过阿尔法贝塔剪枝算法(Alpha-beta pruning)来实现一个高效的人工智能对手。这个算法结合了极大极小搜索(Minimax Search)策略,使得AI在游戏中...

    基于python的AI五子棋实现(极大极小值搜索和alpha beta剪枝)

    在本项目中,我们探索了如何使用Python编程语言来实现一个智能五子棋游戏,它利用了人工智能领域的经典算法——极大极小值搜索(Minimax)以及Alpha-Beta剪枝技术。五子棋是一个简单的二人对弈游戏,但在AI领域却...

    alphabeta剪枝算法的C++实现下棋程序

    《阿尔法贝塔剪枝算法在C++中的应用——打造智能棋类游戏程序》 阿尔法贝塔(Alpha-Beta)剪枝算法是基于搜索树的优化策略,主要用于解决两个玩家的零和博弈问题,例如国际象棋、围棋等棋类游戏。这种算法是A*搜索...

    2019华为杯数学建模F题 第一题 回溯+剪枝 第二题 算到一半 组长换题了,所以在此贡献思路和代码,有缘者继续做下去吧.zip

    总的来说,这个资源揭示了数学建模中的一种常见方法——回溯法及其优化技巧——剪枝,以及它们在解决复杂问题中的作用。对于希望提高解决这类问题能力的人来说,理解和掌握这些概念至关重要。同时,它也提醒我们在...

    人工智能大作业——基于NegaMax(Negated Minimax)和AlphaBeta剪枝等算法实现的简单国际象棋AI

    在这个“人工智能大作业——基于NegaMax(Negated Minimax)和AlphaBeta剪枝等算法实现的简单国际象棋AI”项目中,我们探讨的是如何利用计算机科学中的基础理论来创建一个能够玩国际象棋的人工智能。这个项目可能是...

    人工智能实验报告——井字棋(一字棋)

    **α-β 剪枝** 是极大极小算法的一个优化,用于减少搜索空间。在搜索过程中,算法会维护两个值 α 和 β,分别表示当前节点的最大可能值和最小可能值。当计算机搜索到一个节点时,如果发现该节点的可能结果已经比...

    αβ剪枝五子棋.zip

    α-β剪枝是Minimax算法的一种优化,通过提前排除那些肯定不会影响最优决策的分支,显著减少了搜索的节点数量。α代表AI能获得的最好结果,β代表对手能阻止AI得到的最坏结果。当AI在某个分支上的预测结果不超过α或...

    Qt黑白棋【ab剪枝、迭代加深】

    2. **Alpha-Beta剪枝**:Alpha-Beta剪枝是用于优化最小化极大搜索(Minimax算法)的一种策略,广泛应用于棋类游戏的人工智能。它通过在搜索树中提前剪掉无法改变结果的分支,大大减少了计算量,提高了搜索效率。在这...

    搜索的优化.pdf————电子版_pdf版

    ### 知识点一:搜索优化问题定义 搜索优化问题通常是指在特定的约束条件下,通过一系列动作或选择来找到一个最优解的问题。在这个蛋糕制作案例中,我们面对的是一个搜索算法的优化问题,需要在满足蛋糕体积等于nπ...

    智力拼图游戏——更新

    在这个“智力拼图游戏——更新”中,我们关注的核心是一个基于算法设计的智力挑战,它涉及到回溯法的运用以及可能的剪枝优化策略。首先,我们要理解什么是智力拼图游戏。这类游戏通常要求玩家通过旋转和移动拼图块来...

    javascript gobang AI,JS五子棋AI,源码+教程,基于Alpha-Beta剪枝算法(不是神经网络).zip

    在本资源中,我们主要探讨的是使用JavaScript实现的五子棋AI,该AI采用了一种经典的人工智能算法——Alpha-Beta剪枝。这个项目不仅仅提供了源代码,还附带了教程,使得开发者和学习者能够更好地理解并应用这一算法。...

    α-β剪枝算法实验报告广工(附源码java)

    《α-β剪枝算法在一字棋游戏中的应用——广工实验报告》 实验课程:人工智能 实验项目:α-β剪枝算法 实验者:毛毛 专业班级:未提供 实验日期:2017年10月22日 一、实验内容与背景 本次实验的主要任务是运用α...

    数据结构——迷宫

    《数据结构——迷宫》是一款基于C语言编写的迷宫小游戏,它巧妙地融合了编程技术与游戏设计,为学习者提供了一个实践数据结构和算法的互动平台。在这个游戏中,玩家需要通过解决复杂的路径搜索问题,从起点找到出口...

    人工智能技术导论——博弈树搜索.pdf

    《人工智能技术导论——博弈树搜索》探讨了博弈论中的一个重要概念——博弈树搜索,这是一种在人工智能领域中解决二人博弈问题的策略分析方法。博弈树是通过图形化的方式来表示博弈过程,它反映了双方玩家在博弈过程...

    ACM模版下载——————

    5. **回溯与剪枝**:对于组合优化问题,回溯法是一种有效的解决方案,模版中可能包含深度优先搜索(DFS)和剪枝技巧。 6. **模拟与数学**:很多ACM问题需要通过数学建模和精确计算来解决,模版可能涵盖一些数学函数...

    五子棋——人机对战

    《五子棋——人机对战程序详解》 五子棋是一种深受人们喜爱的双人对弈棋类游戏,其规则简单,但策略深奥,是人工智能领域中的经典研究对象。本文将深入探讨一个实现五子棋人机对战程序的设计与实现,包括算法的选择...

    数据结构课程设计——迷宫问题

    《数据结构课程设计——迷宫问题》是一本针对高校数据结构课程设计的实践教材,由两江大学出版社出版。本书的核心内容是通过迷宫问题来深入理解和应用数据结构,旨在帮助学生将理论知识与实际问题相结合,提升解决...

Global site tag (gtag.js) - Google Analytics