2013 ACM/ICPC 南京网络赛F题

题意:给出一个4×4的点阵,连接相邻点可以构成一个九宫格,每个小格边长为1。从没有边的点阵开始,两人轮流向点阵中加边,如果加入的边构成了新的边长为1的小正方形,则加边的人得分。构成几个得几分,最终完成九宫格时,谁的分高谁赢。现在给出两人前若干步的操作,问接下来两人都采取最优策略的情况下,谁赢。

分析:博弈搜索,有人说要加记忆化,我没有加也过了……与赤裸裸的博弈搜索的区别在于对于最终状态,并不是谁无路可走谁输,而是谁分低谁输。注意判断分数相等的情况。在搜索中每个节点要么是必胜态,要么是必败态,可参见这里对NP问题的描述:http://www.cnblogs.com/rainydays/archive/2011/05/27/2059781.html

边的存储与判断不好处理,我是使用了edge_row[ ][ ]数组来存储横向边,edge_col[ ][ ]来存储纵向边。并用其左边(横向)或上边(纵向)的点来代表这条边。

2013 ACM/ICPC 南京网络赛F题
#include <cstdio>

#include <algorithm>

#include <cstring>

using namespace std;



struct Point

{

    int x, y;

    Point()

    {}

    Point(int x, int y):x(x), y(y)

    {}

};



bool edge_row[5][5];

bool edge_col[5][5];

bool tom_turn;

int edge_num;

int tom_score, jerry_score;



Point get_point(int a)

{

    return Point((a - 1) / 4, (a - 1) % 4);

}



void add_edge(Point a, Point b, bool value)

{

    if (a.x > b.x || a.y > b.y)

        swap(a, b);

    if (a.x == b.x)

        edge_row[a.x][a.y] = value;

    else

        edge_col[a.x][a.y] = value;

}



int square(Point a)

{

    if (a.x < 0 || a.y < 0 || a.x > 2 || a.y > 2)

        return 0;

    bool ret = true;

    ret = ret && edge_row[a.x][a.y];

    ret = ret && edge_col[a.x][a.y];

    ret = ret && edge_row[a.x + 1][a.y];

    ret = ret && edge_col[a.x][a.y + 1];

    if (ret)

        return 1;

    return 0;

}



int get_score(Point a, Point b)

{

    if (a.x > b.x || a.y > b.y)

        swap(a, b);

    if (a.x == b.x)

        return square(Point(a.x - 1, a.y)) + square(a);

    return square(Point(a.x, a.y - 1)) + square(a);

}



void input()

{

    tom_turn = true;

    tom_score = jerry_score = 0;

    scanf("%d", &edge_num);

    memset(edge_row, 0, sizeof(edge_row));

    memset(edge_col, 0, sizeof(edge_col));

    for (int i = 0; i < edge_num; i++)

    {

        int a, b;

        scanf("%d%d", &a, &b);

        Point p1 = get_point(a);

        Point p2 = get_point(b);

        add_edge(p1, p2, true);

        if (tom_turn)

            tom_score += get_score(p1, p2);

        else

            jerry_score += get_score(p1, p2);

        tom_turn = !tom_turn;

    }

}



bool dfs(int next_score, int previous_score, bool tom_turn)

{

    bool win = false;

    bool did = false;

    for (int i = 0; i < 4; i++)

    {

        for (int j = 0; j < 3; j++)

        {

            if (!edge_row[i][j])

            {

                did = true;

                Point a = Point(i, j);

                Point b = Point(i, j + 1);

                add_edge(a, b, true);

                int score = get_score(a, b);

                win = !dfs(previous_score, next_score + score, !tom_turn);

                add_edge(a, b, false);

                if (win)

                    return true;

            }

            if (!edge_col[j][i])

            {

                did = true;

                Point a = Point(j, i);

                Point b = Point(j + 1, i);

                add_edge(a, b, true);

                int score = get_score(a, b);

                win = !dfs(previous_score, next_score + score, !tom_turn);

                add_edge(a, b, false);

                if (win)

                    return true;

            }

        }

    }

    if (!did)

    {

        if (next_score == previous_score)

            return !tom_turn;

        return next_score > previous_score;

    }

    return false;

}



int main()

{

    int case_num;

    scanf("%d", &case_num);

    for (int i = 1; i <= case_num; i++)

    {

        input();

        bool tom_win;

        if (tom_turn)

            tom_win = dfs(tom_score, jerry_score, tom_turn);

        else

            tom_win = !dfs(jerry_score, tom_score, !tom_turn);

        printf("Case #%d: ", i);

        if (tom_win)

            printf("Tom200\n");

        else

            printf("Jerry404\n");

    }

    return 0;

}
View Code

 

你可能感兴趣的:(ICPC)