1. 程式人生 > >CCF201803-4 棋局評估(DFS)

CCF201803-4 棋局評估(DFS)

一道暴力搜尋。由於兩人都以最優策略行棋,故每當輪至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;
}