源哥每日一题第十七弹 poj 1568 Alpha-Beta剪枝

链接:http://poj.org/problem?id=1568

题目:为什么是英文啊题目就是给你一个4*4的OX棋盘,上面已经下了一些棋,然后现在轮到X下,问你有没有一个必胜的方法,有的话就输出坐标,没有输出#####

北大的又一神题。一个很简单的思路很容易就能想到,遍历所有可能的下法,暴力搜看有没有一种情况,无论O怎么下,X都能赢。但是这样复杂度太高了。

然后一个非常神奇的关于棋盘类的博弈搜索方法就出来了:

先说说极大极小搜索法:和正常搜索不同的是,这种搜索限制了搜索深度。当然,搜索到了限定深度之后,非常有可能找不到结果。怎么办呢?给出一个当前状态的得分(估价函数)作为评价当前状态优劣的指标。放到本题,就是对于X越有利的状态,得分越高;对X越不利的状态,得分越低。一个比较成熟的思路就出现了:到X下的时候,找所有儿子里得分最高的;到O下的时候,找所有儿子里得分最低的。

差不多就是这个样子(图片来自北大课件):

 Alpha–beta给出了准确的剪枝方法。

这个剪枝分为两部分:

alpha剪枝:如图:当搜到X的时候,由于R=K>X,所以R的值不会因为X子节点值的改变而改变,所以,可以剪掉X除Y之外的枝。即:当前为极小值X节点,其兄弟节点中,已经找到了最大值a那么在搜索X的时候,如果某个子节点Y<=a,则不用考虑后面的节点了。(极大值剪枝)

beta剪枝:当前为极大值X节点,其兄弟节点中,已经找到了最小值b那么在搜索X的时候,如果某个子节点Y>=b,则不用考虑后面的节点了。(极小值剪枝)

回到这个题。这个题估价函数只有三种情况,既1(胜),0(平),-1(负)也就是说,只要找到一个估价为1的方法就可以。

p.s. 出现了一个神级优化:chess<=4

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
string mp[5];
int X,Y,chess;
int Mindfs(int x,int y, int alpha);
int Maxdfs(int x,int y, int beta);
int jud(char a) {
    if(a=='o') return 1;
    else if(a=='x') return -1;
    else return 0;
}
int chk(int x,int y) {
    int ans = 0;
    for (int i = 0; i < 4; i++) 
        ans+=jud(mp[x][i]);
    if(abs(ans)==4) return 1;
    ans = 0;
    for (int i = 0; i < 4; i++)
        ans+=jud(mp[i][y]);
    if(abs(ans)==4) return 1;
    ans = 0;
    for (int i = 0; i < 4; i++)
        ans+=jud(mp[i][i]);
    if(abs(ans)==4) return 1;
    ans = 0;
    for (int i = 0; i < 4; i++)
        ans+=jud(mp[i][3-i]);
    if(abs(ans)==4) return 1;
    return 0;
}

int Mindfs(int x,int y,int alpha) {
    int ans = 1;
    if (chk(x,y)) return 1;
    if (chess == 16) return 0;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if(mp[i][j] == '.') {
                mp[i][j] = 'o'; 
                chess++;
                int t = Maxdfs(i,j,ans);
                mp[i][j] = '.';
                chess--;
                ans = min(ans,t);
                if(ans <= alpha) {
                    return ans;
                }
            }
        }
    }
    return ans;
}

int Maxdfs(int x,int y,int beta) {
    int ans = -1;
    if (chk(x,y)) return -1;
    if (chess == 16) return 0;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if(mp[i][j] == '.') {
                mp[i][j] = 'x';
                chess++;
                int t = Mindfs(i,j,ans);
                mp[i][j] = '.';
                chess--;
                ans = max(ans,t);
                if(ans >= beta) {
                    return ans;
                }
            }
        }
    }
    return ans;
}

int sol() {
    int alpha = -1;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if(mp[i][j] == '.') {
                mp[i][j] = 'x';
                chess++;
                int t = Mindfs(i,j,alpha);
                mp[i][j] = '.';
                chess--;
                if(t == 1) {
                    X = i; 
                    Y = j;
                    return 1;
                }
            }
        }
    }
    return 0;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("D:\fengyu\Jiang_C\.vscode\in.txt","r",stdin);
	freopen("D:\fengyu\Jiang_C\.vscode\out.txt","w",stdout);
#endif
    string s;
    while(cin >> s && s[0] != '$') {
        chess = 0;
        for (int i = 0; i < 4; i++) {
            cin >> mp[i];
            for (int j = 0; j < 4; j++) {
                chess += mp[i][j] != '.';
            }
        }
        if(chess <= 4 || !sol()) {
            puts("#####");
        } else {
            printf("(%d,%d)
",X,Y);
        }
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/fengyuzhicheng/p/9180918.html