极大极小搜索(α-β剪枝)_C++简单模拟


网上大多数讲α-β剪枝算法的都是从博弈树开始讲起,但是我学过以后发现这样讲不太好理解, 所以打算从与/或树开始讲起,然后再引入博弈树,最后讲α-β剪枝。

与/或树

在解一个问题时,如果构造了一个解空间树求问题的最优解,那么必然是类似的这样一种情况。其中,红色结点为可解结点,有自己的解代价,而黑色结点为不可解结点,解的代价为 + ∞ +∞ +
在这里插入图片描述
但是这样一棵树可以的解代价还无法计算,所以要引入一种解规则。就是与/或规则。一个非叶结点,可以由子节点的与操作(所有情况全部满足)或者或操作(满足一个情况即可)组成。
与操作=max{子节点},或操作=min{子节点}
在这里插入图片描述

博弈树

博弈树就是一种特殊的与/或树。假设有两个绝对理性的人进行棋盘博弈,那么在其中一个人落子时,必然要考虑当前局面的最优解。假设当前棋局对他有一个分值,那么他落子时,需要考虑对他自己最优,对对方最劣的情况。那么博弈树就成了这样一棵与/或树。
博弈树一般是偶数层,因为考虑到最后肯定是对自己的落子,如果是奇数层,就是最后一步考虑了地方落子,变数更大。实际操作中偶数层博弈树的效果也比奇数层要好。
在这里插入图片描述

α-β剪枝

就是对博弈树进行了优化,减少解空间的计算。
对每一个非叶结点,设置一个α和β值,α表示子节点的最大值,β表示子节点的最小值。实际上,一个节点会用到一个值。MAX层的结点用到α,MIN层的结点用到β。
剪枝的思想就是这样:
在这里插入图片描述

前提:任何结点只会对他的父节点产生影响。
满足如下规则的剪枝算法:
1.如果MAX层的α值大于父节点的β值,对当前结点进行剪枝。
2.如果MIN层的β值小于父节点的β值,对当前结点进行剪枝。
至于为什么这么做,可以参考一下α(子节点的最大值)和β(子节点的最小值)的意义,然后想一想就可以想通。
提示一下:

1.如果当前节点在MAX层,那么如果更新α,α只会更大,而当前节点要对父节点(MIN层)产生影响,则α必须比父节点的β更小,如果当前节点的α以及比父节点的β大了,则没有必要继续往下执行,因为当前节点一定不会对父节点产生影响了。

2.如果当前节点在MIN层,那么如果更新β,β只会更小,而当前节点要对父节点(MAX层)产生影响,则β必须比父节点的α更大,如果当前节点的β已经比父节点的α小了,则没有必要往下执行,因为当前节点一定不会对父节点产生影响了。

完整模拟代码

#include<iostream>

using namespace std;

const int MAX = 0x32769;
const int MIN = -1;

int dis;//每个节点的分叉数量
int high;//树的高度,根节点为1

void get(int leave,int &prealpha,int &prebeta) {
	//leave标识当前层数,prealpha标识父节点的alpha,prebeta标识父节点的beta
	int alpha = MIN, beta = MAX;
	if (leave == high) {
		//进入叶子节点,返回一个0~32768的随机数
		int k = rand();//给这个叶子节点一个权值
		if (leave%2 == 0) {
			//上一层是MAX层,可以更新alpha
			if (k > prealpha) {
				prealpha = k;
			}
		}
		else {
			//上一层是MIN层
			if (k < prebeta) {
				prebeta = k;
			}
		}
		cout <<"叶子节点:"<<k <<endl;
		return ;
	}
	if (leave%2 == 0) {
		//当前在MIN层
		for (int i = 0; i < dis; i++) {
			get(leave + 1, alpha, beta);
			if (beta <= prealpha) {
				//剪枝
				break;
			}
		}
		if (beta > prealpha) {
			prealpha = beta;
		}
	}
	else {
		//当前在MAX层
		for (int i = 0; i < dis; i++) {
			get(leave + 1, alpha, beta);
			if (alpha >= prebeta) {
				//剪枝
				break;
			}
		}
		if (alpha < prebeta) {
			prebeta = alpha;
		}
	}
	cout << leave << "层:alpha " << alpha << "  beta " << beta << endl;
}

int main() {
	//alpha-beta剪枝算法,alpha存放最大值,beta存放最小值
	//评估函数用rand函数代替
	cout << "请输入博弈树的高度(根节点为第一层,high<=5)" << endl;
	cin >> high;					//读入叶子节点的数量
	cout << "请输入每个节点的分叉数" << endl;
	cin >> dis;
	int alpha = MIN, beta = MAX;
	for (int i = 0; i < dis; i++) {
		get(2, alpha, beta);//根节点不需要剪枝      
	}
	cout << endl;
	cout << alpha << endl;
	return 0;
}

结果如下:
在这里插入图片描述

  • 4
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
极大极小算法(Minimax Algorithm)是一种博弈树算法,常用于人工智能领域中的决策树问题。该算法通过递归地搜索博弈树,找到最优的下一步决策。在搜索过程中,假设对手会采取最优策略,因此算法会选择对自己最有利的决策,同时也会考虑到对手的最优策略,以避免自己处于劣势。 C语言实现极大极小算法的步骤如下: 1. 定义博弈树的节点结构体,包括当前状态、当前玩家、当前深度等信息。 2. 定义估值函数,用于评估当前状态的价值。 3. 定义maxSearch和minSearch函数,分别代表当前玩家为MAX和MIN的情况下的搜索过程。在搜索过程中,需要递归地搜索子节点,并计算出每个子节点的估值。 4. 在maxSearch和minSearch函数中,根据当前玩家的不同,选择最大或最小的估值,并返回该估值。 5. 在主函数中,调用maxSearch函数,得到最优的下一步决策。 下面是一个简单的C语言实现极大极小算法的示例代码: ```c #include <stdio.h> #include <stdlib.h> #define MAX_DEPTH 5 // 定义博弈树的节点结构体 typedef struct node { int state; int player; int depth; struct node *children[3]; } Node; // 估值函数 int evaluate(int state) { if (state == 1) { return 1; } else if (state == -1) { return -1; } else { return 0; } } // maxSearch函数 int maxSearch(Node *node) { if (node->depth == MAX_DEPTH) { return evaluate(node->state); } int maxVal = -100; for (int i = 0; i < 3; i++) { if (node->children[i] == NULL) { node->children[i] = (Node *)malloc(sizeof(Node)); node->children[i]->state = -node->player; node->children[i]->player = -node->player; node->children[i]->depth = node->depth + 1; } int val = minSearch(node->children[i]); if (val > maxVal) { maxVal = val; } } return maxVal; } // minSearch函数 int minSearch(Node *node) { if (node->depth == MAX_DEPTH) { return evaluate(node->state); } int minVal = 100; for (int i = 0; i < 3; i++) { if (node->children[i] == NULL) { node->children[i] = (Node *)malloc(sizeof(Node)); node->children[i]->state = -node->player; node->children[i]->player = -node->player; node->children[i]->depth = node->depth + 1; } int val = maxSearch(node->children[i]); if (val < minVal) { minVal = val; } } return minVal; } int main() { Node *root = (Node *)malloc(sizeof(Node)); root->state = 0; root->player = 1; root->depth = 0; for (int i = 0; i < 3; i++) { root->children[i] = NULL; } int bestVal = -100; int bestMove = -1; for (int i = 0; i < 3; i++) { root->children[i] = (Node *)malloc(sizeof(Node)); root->children[i]->state = -root->player; root->children[i]->player = -root->player; root->children[i]->depth = root->depth + 1; int val = minSearch(root->children[i]); if (val > bestVal) { bestVal = val; bestMove = i; } } printf("Best move: %d\n", bestMove); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值