uva 11623 - Tic Tac Toe(game)

Problem A: Tic Tac Toe

The game of Tic Tac Toe is played on an n-by- n grid (where n is usually but not necessarily three). Two players alternate placing symbols on squares of the grid. One player places Xes and the other player places Os. The player placing Xes always goes first. When the grid contains a vertical, horizontal, or diagonal sequence of at least m consecutive squares all containing the same symbol, the game ends and the winner is the player who placed the last symbol. When all the squares of the grid are filled, if neither player has won, the game ends in a draw.

Your task is to analyze the state of a Tic Tac Toe board, and determine whether the game is still in progress, or if it has completed, who won, or if the game ended in a draw. You should also detect erroneous states of the Tic Tac Toe board that could never occur during an actual game.

Input Specification

The first line of input contains a single integer, the number of test cases to follow. The first line of each test case contains the two integers n and m, separated by spaces, with 1 <= m <= n <= 1000. The following n lines of the test case each contain one row of the Tic Tac Toe board. Each of these lines contains exactly n characters, and each of these characters is either an X, an O, or a period ( .), indicating an empty square.

Sample Input

1
3 3
..X
OOX
..X

Output Specification

For each test case, output a single line containing the appropriate string X WINS, O WINS, or DRAW if the game is over, the string IN PROGRESS if the game has not yet finished, or ERROR if the state of the board could never occur during a game.

Output for Sample Input

X WINS
 
这题关键是ERROR的情况,我总结如下:
1、'X'出现的比'O'少,则输出ERROR;
2、'X'出现次数和'O'出现次数相差超过1,则输出ERROR;
3、'X'和'O'都赢了,,则输出ERROR;
4、'X'赢的时候,'X'出现的次数和'O'出现次数相差不是1,则输出ERROR;(因为'X'是先手)
5、赢者连续的长度必须 < 2*m,否则输出ERROR;(因为>=2*m的话,说明之前就已经赢了,然后结束了)
6、若赢者有多个长度满足要求必定交于一点,而且交点两边的长度一定要 < m,否则输出ERROR;
以上条件最难判断的是最后一个,我首先用dfs得到交点,然后在做判断。下面具体说明:
1、sum[maxn][maxn][5];//用数组记录当前格子的位置和4个方向的最长长度:

这样每个连续的最长长度就可以求出来了!//0 行 1 列 2 左斜 3 右斜
2、
struct position{
    int x , y , dir;
    position(int a = 0 , int b = 0 , int c = 0){
        x = a , y = b , dir = c;
    }
};//用结构体记录连续长度超过m是的点和它的方向;
比如:
6 3
X.....
X....O
XXO...
X.XOO.
X.....
...OO.
我就记录了(2,0)(3,0)(4,0)(3,2)这4个点和来自的方向,
3、
vis[maxn][maxn]数组在调用dfs()找交点的时候用,初始为0,记录的是当前这个格子有多少条路经过,每次从2中的记录的点
为入口往前递归,最后如果发现有一个点经过路径的条数==2中记录的点的个数,那么这个点就是交点,如果没有发现这个点,
说明当前这个图是ERROR。这个点记为(centerX , centerY)。
如果有路径在这个点的前半段或后半段(不包括交点) >= m那么这个图是错误的。如果是前半段>=m,用刚才的dfs()找交点
是找不到的,所以很巧妙地避开了前半段的情况,不信在纸上画画写写就知道为什么了!现在只要考虑后半段。后半段只要有2
中的点到交点的长度(不包括交点)>=m,那么就是错误的,这个很好判断吧~
特别注意:
1 1
X
X WINS
完毕!
 
#include <iostream>
#include <cstdio>
#include <string>
#include <map>
#include <vector>
#include <cmath>
using namespace std;

struct position{
    int x , y , dir;
    position(int a = 0 , int b = 0 , int c = 0){
        x = a , y = b , dir = c;
    }
};
vector<position> X_p , O_p;
const int maxn = 1010;
const int dr[4] = {0 , 1 , 1 , 1};
const int dl[4] = {1 , 0 , -1 ,1};
string mp[maxn];
map<char , int> total;
int X_sum , O_sum , sum[maxn][maxn][5] , n , m , vis[maxn][maxn] , centerX , centerY;
bool ERROR;
//0 行 1 列 2 左斜 3 右斜

void initial(){
    for(int i = 0; i < maxn; i++){
        for(int j = 0; j < maxn; j++){
            for(int k = 0; k < 5; k++){
                sum[i][j][k] = 0;
            }
            vis[i][j] = 0;
        }
        mp[i].clear();
    }
    X_sum = 0;
    O_sum = 0;
    total['X'] = 0;
    total['O'] = 0;
    ERROR = false;
    centerX = 0;
    centerY = 0;
    X_p.clear();
    O_p.clear();
}

void readcase(){
    scanf("%d%d" , &n, &m);
    for(int i = 0; i < n; i++){
        cin >> mp[i];
    }
}

void computing(){
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            if(mp[i][j] == 'X'){
                total['X']++;
                for(int k = 0; k < 4; k++){
                    sum[i][j][k]++;
                    if(m <= sum[i][j][k]){
                        X_sum = 1;
                        X_p.push_back(position(i , j , k));
                    }
                    if(sum[i][j][k] >= 2*m){
                        ERROR = true;
                        return;
                    }
                    int r = i+dr[k] , c = j+dl[k];
                    if(r >= 0 && r < n && c >= 0 && c < n && mp[r][c] == 'X'){
                        sum[r][c][k] = max(sum[r][c][k] , sum[i][j][k]);
                    }
                }
            }
            if(mp[i][j] == 'O'){
                total['O']++;
                for(int k = 0; k < 4; k++){
                    sum[i][j][k]++;
                    if(m <= sum[i][j][k]){
                        O_sum = 1;
                        O_p.push_back(position(i , j , k));
                    }
                    if(sum[i][j][k] >= 2*m){
                        ERROR = true;
                        return;
                    }
                    int r = i+dr[k] , c = j+dl[k];
                    if(r >= 0 && r < n && c >= 0 && c < n && mp[r][c] == 'O'){
                        sum[r][c][k] = max(sum[r][c][k] , sum[i][j][k]);
                    }
                }
            }
        }
    }
}

bool dfs(int i , int j , int k , int psize , char player){
    vis[i][j]++;
    if(vis[i][j] == psize){
        centerX = i;
        centerY = j;
        return true;
    }
    int r = i-dr[k] , c = j-dl[k];
    if(r >= 0 && r < n && c >= 0 && c < n && mp[r][c] == player){
        if(dfs(r , c , k , psize , player)) return true;
    }
    return false;
}

void out(){
    if(ERROR || total['X'] < total['O']){
        printf("ERROR\n");
        return;
    }
    if(total['X']+total['O'] == n*n){
        if(total['X'] == total['O'] || total['X']-total['O'] == 1){
			if(n == 1) printf("X WINS\n");
			else printf("DRAW\n");
        }
        else printf("ERROR\n");
        return;
    }

    if(total['X']-total['O'] < -1 || total['X']-total['O'] > 1){
        printf("ERROR\n");
        return;
    }
    if(X_sum && O_sum){
        printf("ERROR\n");
        return;
    }
    if(X_sum){
        if(total['X'] - total['O'] != 1){
            printf("ERROR\n");
            return;
        }
        for(int i = 0; i < X_p.size(); i++){
            if(dfs(X_p[i].x , X_p[i].y , X_p[i].dir , X_p.size() , 'X')){
                for(int j = 0; j < X_p.size(); j++){
                    if(abs(X_p[j].x-centerX)+1 > m || abs(X_p[j].y-centerY)+1 > m){
                        
                        printf("ERROR\n");
                        return;
                    }
                }
                printf("X WINS\n");
                return;
            }
        }
        printf("ERROR\n");
        return;
    }
    if(O_sum){
        if(total['X'] != total['O']){
            printf("ERROR\n");
            return;
        }
        for(int i = 0; i < O_p.size(); i++){
            if(dfs(O_p[i].x , O_p[i].y , O_p[i].dir , O_p.size() , 'O')){
                for(int j = 0; j < O_p.size(); j++){
                    if(abs(O_p[j].x-centerX)+1 > m || abs(O_p[j].y-centerY)+1 > m){
                        printf("ERROR\n");
                        return;
                    }
                }
                printf("O WINS\n");
                return;
            }
        }
        printf("ERROR\n");
        return;
    }
    printf("IN PROGRESS\n");
}

int main(){
    int t;
    scanf("%d" , &t);
    while(t--){
        initial();
        readcase();
        computing();
        out();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值