CCF201803-4 棋局評估(DFS)
阿新 • • 發佈:2019-01-07
一道暴力搜尋。由於兩人都以最優策略行棋,故每當輪至1或2時,都對棋盤當前剩餘的所有可走位置進行回溯dfs,以得出當前局面的最優結果。又因為1勝時得分為正,2勝時得分為負,故計算最值時,對1使用max,對2使用min。
下面是帶註釋的程式碼:
#include <bits/stdc++.h> #define ll long long #define INF 0x3f3f3f3f using namespace std; int g[4][4]; bool read() { memset(g, 0, sizeof(g)); bool flag = false; for(int i = 1; i <= 3; ++i) for(int j = 1; j <= 3; ++j) { cin >> g[i][j]; if(g[i][j]) flag = true; } return flag; } int judge() //返回當前局面的勝者的編號 { for(int i = 1; i <= 3; ++i) { if(g[i][1] != 0 && g[i][1] == g[i][2] && g[i][2] == g[i][3]) return g[i][1]; if(g[1][i] != 0 && g[1][i] == g[2][i] && g[2][i] == g[3][i]) return g[1][i]; } if(g[2][2] != 0 && g[1][1] == g[2][2] && g[2][2] == g[3][3]) return g[2][2]; if(g[2][2] != 0 && g[1][3] == g[2][2] && g[2][2] == g[3][1]) return g[2][2]; return 0; } int dfs(int s) //s記錄當前下棋者的編號 { int sum = 0, win = judge(); for(int i = 1; i <= 3; ++i) for(int j = 1; j <= 3; ++j) if(!g[i][j]) sum++; //可走位置的數量 if(win == 1) return sum+1; //1勝,返回1的得分 if(win == 2) return -(sum+1); //2勝,返回2的得分 if(!sum) return 0; //無位置可走,此時平局,兩人得分都為0 int maxn = -INF, minn = INF; for(int i = 1; i <= 3; ++i) for(int j = 1; j <= 3; ++j) if(!g[i][j]) { g[i][j] = s; //s將棋下在這裡 if(s == 1) //1走完,輪到2下 maxn = max(maxn, dfs(2)); //得到最優策略下的得分 if(s == 2) minn = min(minn, dfs(1)); g[i][j] = 0; //回溯 } if(s == 1) return maxn; if(s == 2) return minn; } void solve() { if(!read()) { cout << 0 << '\n'; //當棋盤為空時,特判 return; } else cout << dfs(1) << '\n' ; //1先走棋 } int main() { int t; cin >> t; while(t--) solve(); return 0; }