源哥每日一题第十七弹 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_JUDGEfreopen("D:\\fengyu\\Jiang_C\\.vscode\\in.txt","r",stdin);freopen("D:\\fengyu\\Jiang_C\\.vscode\\out.txt","w",stdout); #endifstring 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)\n",X,Y);}}return 0; }
轉載于:https://www.cnblogs.com/fengyuzhicheng/p/9180918.html
總結
以上是生活随笔為你收集整理的源哥每日一题第十七弹 poj 1568 Alpha-Beta剪枝的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaWeb学习之Spring框架(一
- 下一篇: Python爬虫之BeautifulSo