CCF201803-4-棋局评估 (对抗搜索)

原题地址:http://118.190.20.162/view.page?gpid=T70

思路:具体参考博客
然后这里因为是3*3的格子,所以情况不多,主要是用到了极小值极大值策略,如果数据再大,需要用到a-b剪枝。

具体ac代码:

#include 
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
int t;
int a[5][5];
bool okrow(int f, int x) {//表示第f个人,第x行
    return a[x][1] == f && a[x][2] == a[x][1] && a[x][1] == a[x][3];
}

bool okcol(int f, int x) { //表示第f个人,第x列
    return a[1][x] == f && a[1][x] == a[2][x] && a[2][x] == a[3][x];
}

bool okxie(int f) {//判断井字棋斜着能不能赢
    if (a[1][1] == f && a[2][2] == a[1][1] && a[1][1] == a[3][3]) return 1;
    if (a[3][1] == f && a[2][2] == a[3][1] && a[1][3] == a[2][2]) return 1;
    return 0;
}

int check(int f) {//判断当前棋盘分数
    int ans = 1;
    for (int i = 1; i <= 3; i++) {
        for (int j = 1; j <= 3; j++) {
            if (a[i][j] == 0) ans++;
        }
    }
    if (f == 1) return ans;
    else return -ans;
}
bool win(int f) {//判断f能不能赢
    if (okrow(f, 1) || okrow(f, 2) || okrow(f, 3)) return 1;
    if (okcol(f, 1) || okcol(f, 2) || okcol(f, 3)) return 1;
    if (okxie(f)) return 1;
    return 0;
}
int dfs(int peo) { //1表示alice 2表示bob下棋
    if (check(1) == 1) return 0;//如果没有位置可以填了,那么就是平局
    int MAX = -INF;//初始化最大值
    int MIN = INF;//初始化最小值
    for (int i = 1; i <= 3; i++) {
        for (int j = 1; j <= 3; j++) {
            if (a[i][j]) continue;
            a[i][j] = peo;//给当前位置赋值
            if (win(peo)) {//如果下了这个棋子之后能赢
                if (peo == 1) MAX = max(MAX, check(1));//比较
                else MIN = min(MIN, check(2));
                a[i][j] = 0;//回溯
                continue;
            }
            //下了棋子之后不能赢,那么就需要继续递归
            if (peo == 1) {
                MAX = max(MAX, dfs(2));
            } else {
                MIN = min(MIN, dfs(1));
            }
            a[i][j] = 0;//回溯
        }
    }
    if (peo == 1) return MAX;
    else return MIN ;
}
int main() {
    scanf("%d", &t);
    while (t--) {
        for (int i = 1; i <= 3; i++) {
            for (int j = 1; j <= 3; j++) {
                scanf("%d", &a[i][j]);
            }
        }
        int x = win(1);//初始棋面Alice能赢
        int y = win(2);//初始棋Bob能赢
        if (x) printf("%d\n", check(1));
        else if (y) printf("%d\n", check(2));
        else printf("%d\n", dfs(1));
    }
    return 0;
}

你可能感兴趣的:(ACM_搜索)