对抗搜索(学习了)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_25576697/article/details/82147740

https://blog.csdn.net/weixin_39278265/article/details/80930233

ccf能力认证(201803-4)

问题描述

试题编号: 201803-4
试题名称: 棋局评估
时间限制: 1.0s
内存限制: 256.0MB
问题描述:

问题描述

  Alice和Bob正在玩井字棋游戏。
  井字棋游戏的规则很简单:两人轮流往3*3的棋盘中放棋子,Alice放的是“X”,Bob放的是“O”,Alice执先。当同一种棋子占据一行、一列或一条对角线的三个格子时,游戏结束,该种棋子的持有者获胜。当棋盘被填满的时候,游戏结束,双方平手。
  Alice设计了一种对棋局评分的方法:
  - 对于Alice已经获胜的局面,评估得分为(棋盘上的空格子数+1);
  - 对于Bob已经获胜的局面,评估得分为 -(棋盘上的空格子数+1);
  - 对于平局的局面,评估得分为0;


  例如上图中的局面,Alice已经获胜,同时棋盘上有2个空格,所以局面得分为2+1=3。
  由于Alice并不喜欢计算,所以他请教擅长编程的你,如果两人都以最优策略行棋,那么当前局面的最终得分会是多少?

输入格式

  输入的第一行包含一个正整数T,表示数据的组数。
  每组数据输入有3行,每行有3个整数,用空格分隔,分别表示棋盘每个格子的状态。0表示格子为空,1表示格子中为“X”,2表示格子中为“O”。保证不会出现其他状态。
  保证输入的局面合法。(即保证输入的局面可以通过行棋到达,且保证没有双方同时获胜的情况)
  保证输入的局面轮到Alice行棋。

输出格式

  对于每组数据,输出一行一个整数,表示当前局面的得分。

样例输入

3
1 2 1
2 1 2
0 0 0
2 1 1
0 2 1
0 0 2
0 0 0
0 0 0
0 0 0

样例输出

3
-4
0

样例说明

  第一组数据:
  Alice将棋子放在左下角(或右下角)后,可以到达问题描述中的局面,得分为3。
  3为Alice行棋后能到达的局面中得分的最大值。
  第二组数据:


  Bob已经获胜(如图),此局面得分为-(3+1)=-4。
  第三组数据:
  井字棋中若双方都采用最优策略,游戏平局,最终得分为0。

数据规模和约定

  对于所有评测用例,1 ≤ T ≤ 5。

题意:两人下井字棋,现在给你一个残局棋盘,两人都最优策略下棋,问最后分数情况。

思路:在搜索树中每个节点,下棋的人都选择对自己最有利的子树走。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[3][3];
bool hok(int val,int x)
{
    if(a[x][0]==val&&a[x][1]==val&&a[x][2]==val)
    {
        return true;
    }
    return false;
}
bool lok(int val,int y)
{
    if(a[0][y]==val&&a[1][y]==val&&a[2][y]==val)
    {
        return true;
    }
    return false;
}
int check()
{
    int ans = 0;
    for(int i = 0;i<3;i++)
    {
        for(int j = 0;j<3;j++)
        {
            if(a[i][j]==0)ans++;
        }
    }
    return ans;
}
int win(int x)
{
    int w = 0,ans = 1;
    if(hok(x,0)||hok(x,1)||hok(x,2))w=1;
    if(lok(x,0)||lok(x,1)||lok(x,2))w=1;
    if(a[0][0]==x&&a[1][1]==x&&a[2][2]==x)w=1;
    if(a[0][2]==x&&a[1][1]==x&&a[2][0]==x)w=1;
    if(!w)return 0;
    ans +=check();
    return ans*(x==1?1:-1);
}
int dfs(int p,int step)
{
    if(step==0)
    {
        return 0;
    }
    int Min = 10,Max = -10;
    for(int i = 0;i<3;i++)
    {
        for(int j =0;j<3;j++)
        {
            if(!a[i][j])
            {
                a[i][j] = p+1;
                int w = win(p+1);
                if(w)
                {
                    a[i][j] =0;
                    return w>0?max(Max,w):min(Min,w);
                }
                else
                {
                    if(!p)Max = max(Max,dfs(1,step-1));
                    else Min = min(Min,dfs(0,step-1));
                }
                a[i][j] = 0;
            }
        }
    }
    return p?Min:Max;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int cnt = 0;
        for(int i = 0;i<3;i++)
        {
            for(int j = 0;j<3;j++)
            {
                scanf("%d",&a[i][j]);
                if(a[i][j]==1)cnt++;
            }
        }
        int x = win(1),y = win(2);
        if(x){
            printf("%d\n",x);
        }
        else if(y)
        {
            printf("%d\n",y);
        }
        else printf("%d\n",dfs(0,9-cnt*2));
    }
}

计蒜客 rake_it_in

The designers have come up with a new simple game called “Rake It In”. Two players, Alice and Bob, initially select an integer k and initialize a score indicator. An 4 \times 44×4 board is created with 16 values placed on the board. Starting with player Alice, each player in a round selects a 2 \times 22×2 region of the board, adding the sum of values in the region to the score indicator, and then rotating these four values 9090 degrees counterclockwise.

After 22k rounds in total, each player has made decision in k times. The ultimate goal of Alice is to maximize the final score. However for Bob, his goal is to minimize the final score.

In order to test how good this game is, you are hired to write a program which can play the game. Specifically, given the starting configuration, they would like a program to determine the final score when both players are entirely rational.

Input

The input contains several test cases and the first line provides an integer t (1 \le t \le 200)t(1≤t≤200) which is the number of test cases.

Each case contains five lines. The first line provides the integer k (1 \le k \le 3)k(1≤k≤3). Each of the following four lines contains four integers indicating the values on the board initially. All values are integers between 11 to 1010.

Output

For each case, output an integer in a line which is the predicted final score.

样例输入

4
1
1 1 2 2
1 1 2 2  
3 3 4 4  
3 3 4 4
2
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
3  
1 1 4 4
4 4 1 1
1 1 4 4
1 4 1 4
3  
1 2 3 4
5 1 2 3
4 5 1 2
3 4 5 1

样例输出

20
40
63
71

题意:两人对一个4x4的矩阵每一回合每个人都做同样的操作(选择一个2x2的子矩阵,将其和加入sum中,并将其逆时针90度翻转),一个人想要结束后sum值大,一个人想要sum值小,问最后sum值是多少。

思路:类似。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[4][4];
int k1;
void rotate(int i,int j,int type)
{
    int tmp;
    if(type==-1)
    {
        tmp = a[i][j];
        a[i][j] = a[i+1][j];
        a[i+1][j] = a[i+1][j+1];
        a[i+1][j+1] = a[i][j+1];
        a[i][j+1] = tmp;
    }
    else
    {
        tmp = a[i][j];
        a[i][j] = a[i][j+1];
        a[i][j+1] = a[i+1][j+1];
        a[i+1][j+1] = a[i+1][j];
        a[i+1][j] = tmp;
    }
}
int dfs(int p,int k)
{
    if(k==2*k1)
    {
        int Min = 0x3f3f3f3f;
        for(int i = 0;i<3;i++)
        {
            for(int j = 0;j<3;j++)
            {
                int res = a[i][j]+a[i+1][j]+a[i][j+1]+a[i+1][j+1];
                Min = min(Min,res);
            }
        }   
        return Min; 
    }
    int Min = 0x3f3f3f3f,Max = 0;
    for(int i = 0;i<3;i++)
    {
        for(int j = 0;j<3;j++)
        {
            int res = a[i][j]+a[i+1][j]+a[i][j+1]+a[i+1][j+1];
            rotate(i,j,1);
            if(p==0)
            {
                Max = max(Max,dfs(1,k+1)+res);
            }
            else
            {
                Min = min(Min,dfs(0,k+1)+res);
            }
            rotate(i,j,-1);
        }
    }
    return ((!p)?Max:Min);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&k1);
        for(int i = 0;i<4;i++)
        {
            for(int j = 0;j<4;j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        printf("%d\n",dfs(0,1));
    }
}

猜你喜欢

转载自blog.csdn.net/qq_25576697/article/details/82147740
今日推荐