博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
算法笔记--极大极小搜索及alpha-beta剪枝
阅读量:6034 次
发布时间:2019-06-20

本文共 7932 字,大约阅读时间需要 26 分钟。

参考1:

参考2:

参考3:

极小极大搜索算法即minimax搜索算法

主要应用于零和博弈(非胜即负,如围棋,象棋,井子棋等),完全信息(玩家知道之前所有的步骤。象棋就是完全信息,因为玩家是交替着落子,且之前的步骤都能在棋盘上体现)

这个算法采用搜索算法递归实现,一层为先手,记为a, 一层为后手,记为b, 交替出现

对于最终局面,有一个分数(比如:先手胜分数为1, 平局分数为0,先手输分数为-1)

先手a想要让这个分数越大越好,后手b想要让这个分数越小越好,于是搜索到先手这一层,取最大返回,搜索到后手这一层,取最小返回

如下图:

 

于是伪代码为:

int MaxMin(position,int d){    int bestvalue,value;    if(game over)   //检查游戏是否结束         return evaluation(p);// 游戏结束,返回估值     if(depth<=0)    //检查是否是叶子节点         return evaluation(p);//叶子节点,返回估值     if(max)         //极大值点         bestvalue=-INFINTY;    else            //极小值点         bestvalue=INFINTY;    for(each possibly move m)    {        MakeMove(m);    //走棋         value=MaxMin(p,d-1);        UnMakeMove(m);  //恢复当前局面         if(max)            bestvalue=max(value,bestvalue);//取最大值         else            bestvalue=min(value,bestvalue);//取最小值     }    return bestvalue;}

 关于alpha-beta剪枝:

如果当前层为取最小,如果取最小后比上一层当前最大值还小,则不需要往下搜索,因为上一层根本不会选择当前节点往下搜,还有更好的选择

同理,如果当前层为取最大,如果取最大后比上一层当前最小值还大,则不需要往下搜索,因为上一层根本不会选择当前节点往下搜

具体推荐看最上面的知乎链接点赞最多的回答。

alpha-beta剪枝后的伪代码:

int AlphaBeta(nPlay,nAlpha,nBeta){    if(game over)        return Eveluation;   //胜负已分,返回估值    if(nPly==0)        return  Eveluation;  //叶子节点返回估值    if(Is Min Node)          //判断 节点类型     {        // 极小值节点        for(each possible move m)        {            make move m;      //生成新节点            score=AlphaBeta(nPly-1,nAlpha,nBeta)//递归搜索子节点            unmake move m;//撤销搜索过的节点            if(score
=nBeta) return nAlpha;//alpha剪枝,抛弃后继节点 } } return nBeta;//返回最小值 } else {
//取极大值的节点 for(each possible move m) { make move m; //生成新节点 score=AlphaBeta(nPly-1,nAlpha,nBeta)//递归搜索子节点 unmake move m;//撤销搜索过的节点 if(score>nAlpha) { nAlpha=score;//取极小值 if(nAlpha>=nBeta) return nBeta;//nBeta剪枝,抛弃后继节点 } } return nAlpha;//返回最小值 } }

例题1:

思路:井子棋下的步数小于等于4必平局

代码:

#pragma GCC optimize(2)#pragma GCC optimize(3)#pragma GCC optimize(4)#include
#include
using namespace std;#define fi first#define se second#define pi acos(-(long double)1.0)#define LL long long//#define mp make_pair#define pb push_back#define ls rt<<1, l, m#define rs rt<<1|1, m+1, r#define ULL unsigned LL#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);#define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout);//headchar s[10], mp[10][10]; int cnt = 0, ansx, ansy;int check(char c) { for (int i = 0; i < 4; i++) { int a = 0; for (int j = 0; j < 4; j++) { if(mp[i][j] == c) a++; } if(a == 4) return 1; a = 0; for (int j = 0; j < 4; j++) { if(mp[j][i] == c) a++; } if(a == 4) return 1; } int a = 0; for (int i = 0; i < 4; i++) if(mp[i][i] == c) a++; if(a == 4) return 1; a = 0; for (int i = 0; i < 4; i++) if(mp[i][3-i] == c) a++; if(a == 4) return 1; return 0;}int dfs(int step, int a, int b) { if((cnt-step)%2 == 0) { int tmp = check('o'); if(tmp || step == 0) return -tmp; } else { int tmp = check('x'); if(tmp || step == 0) return tmp; } if((cnt-step)%2 == 0) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if(mp[i][j] == '.') { mp[i][j] = 'x'; int tmp = dfs(step-1, a, b); mp[i][j] = '.'; if(tmp >= a) { if(step == cnt) { ansx = i; ansy = j; } a = tmp; if(b <= a) return b; } } } } return a; } else { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if(mp[i][j] == '.') { mp[i][j] = 'o'; int tmp = dfs(step-1, a, b); mp[i][j] = '.'; if(tmp <= b) { b = tmp; if(a >= b) return a; } } } } return b; }}int main() { while(~scanf("%s", s)) { if(s[0] == '$') return 0; for (int i = 0; i < 4; i++) scanf("%s", mp[i]); cnt = 0; for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) if(mp[i][j] == '.') cnt++; if(cnt >= 12) { printf("#####\n"); continue; } int ans = dfs(cnt, -1, 1); if(ans == 1) printf("(%d,%d)\n", ansx, ansy); else printf("#####\n"); } return 0;}
View Code

例题2:

思路1:记忆化搜索dp, dp[s]表示从状态s出发先手所能获得的最大利益。

特点:空间大,时间短

代码:

#pragma GCC optimize(2)#pragma GCC optimize(3)#pragma GCC optimize(4)#include
#include
#include
#include
#include
#include
using namespace std;#define fi first#define se second#define pi acos(-1.0)#define LL long long//#define mp make_pair#define pb push_back#define ls rt<<1, l, m#define rs rt<<1|1, m+1, r#define ULL unsigned LL#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);#define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout);//headint line[18][2] = { { 1, 2}, { 1, 3}, { 2, 3}, { 2, 4}, { 2, 5}, { 4, 5}, { 3, 5}, { 3, 6}, { 5, 6}, { 4, 7}, { 4, 8}, { 7, 8}, { 5, 8}, { 5, 9}, { 8, 9}, { 6, 9}, { 6, 10}, { 9, 10}};int tri[9][3] = { { 0, 1, 2}, { 3, 4, 5}, { 6, 7, 8}, { 9, 10, 11}, { 12, 13, 14}, { 15, 16, 17}, { 2, 4, 6}, { 5, 10, 12}, { 8, 13, 15}};int num[11][11];int dp[1<<20];int count(int s) { int cnt = 0; for (int i = 0; i < 9; i++) if((s&(1<
prenum) { if(step%2 == 0) cnt += nownum - prenum; else cnt -= nownum - prenum; } else step++; prenum = nownum; } if(step%2 == 0) cnt += dfs(st); else cnt -= dfs(st); if(cnt > 0) printf("Game %d: A wins.\n", cs); else printf("Game %d: B wins.\n", cs); } return 0;}
View Code

思路2:极大极小搜索+alpha-beta剪枝

特点:空间小,时间长

代码:

#pragma GCC optimize(2)#pragma GCC optimize(3)#pragma GCC optimize(4)#include
#include
#include
#include
#include
#include
using namespace std;#define fi first#define se second#define pi acos(-1.0)#define LL long long//#define mp make_pair#define pb push_back#define ls rt<<1, l, m#define rs rt<<1|1, m+1, r#define ULL unsigned LL#define pll pair
#define pli pair
#define pii pair
#define piii pair
#define pdd pair
#define mem(a, b) memset(a, b, sizeof(a))#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);#define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout);//headint line[18][2] = { { 1, 2}, { 1, 3}, { 2, 3}, { 2, 4}, { 2, 5}, { 4, 5}, { 3, 5}, { 3, 6}, { 5, 6}, { 4, 7}, { 4, 8}, { 7, 8}, { 5, 8}, { 5, 9}, { 8, 9}, { 6, 9}, { 6, 10}, { 9, 10}};int tri[9][3] = { { 0, 1, 2}, { 3, 4, 5}, { 6, 7, 8}, { 9, 10, 11}, { 12, 13, 14}, { 15, 16, 17}, { 2, 4, 6}, { 5, 10, 12}, { 8, 13, 15}};int num[11][11];int count(int s) { int cnt = 0; for (int i = 0; i < 9; i++) if((s&(1<
b) return 1; else return -1; } int prenum = count(s); for(int i = 0; i < 18; i++) { if(!(s&(1<
= alpha) { alpha = tmp; if(alpha >= beta) return alpha; } } else { int tmp = dfs(s|1<
= beta) return beta; } } } else { if(step%2 == 0) { int tmp = dfs(s|1<
= alpha) { alpha = tmp; if(alpha >= beta) return alpha; } } else { int tmp = dfs(s|1<
= beta) return beta; } } } } } if(step%2 == 0) return alpha; else return beta;}int main() { int T, m, u, v; for (int i = 0; i < 18; i++) num[line[i][0]][line[i][1]] = num[line[i][1]][line[i][0]] = i; scanf("%d", &T); for(int cs = 1; cs <= T; cs++) { int st = 0; scanf("%d", &m); int prenum = 0, nownum = 0; int step = 0, a = 0, b = 0; for (int i = 1; i <= m; i++) { scanf("%d %d", &u, &v); st |= 1<
prenum) { if(step%2 == 0) a += nownum - prenum; else b += nownum - prenum; } else step++; prenum = nownum; } int cnt = dfs(st, a, b, -1, 1, step); if(cnt > 0) printf("Game %d: A wins.\n", cs); else printf("Game %d: B wins.\n", cs); } return 0;}
View Code

 

转载于:https://www.cnblogs.com/widsom/p/10153159.html

你可能感兴趣的文章
分享职场心得《3》
查看>>
ModeBusRtu概述
查看>>
学习之路-现代密码学基础-001
查看>>
缓存遇到的数据过滤与分页问题
查看>>
实验05博客园总结
查看>>
(转)shell中括号的特殊用法 linux if多条件判断
查看>>
zabbix监控多tomcat实例
查看>>
CSS定宽居中的实现方案
查看>>
Elasticsearch5.x 升级
查看>>
vue中嵌套页面(iframe)
查看>>
[古怪问题] Marshal.GetActiveObject 在管理员模式下无法正常运行
查看>>
1600802047 android 第三次作业(音乐播放器)
查看>>
初窥Linux 之 最常用20条命令
查看>>
Vue优化首页加载速度 CDN引入
查看>>
DML数据操作语言之常用函数
查看>>
angular搭建
查看>>
网络编程 --ftp01上传
查看>>
CentOS 6.5升级Python和安装IPython(亲测可用)
查看>>
cocos2d基本类介绍 director/scene/layer/sprite
查看>>
生成、打包、部署和管理应用程序及类型(3):将模块合并成程序集
查看>>