2013 ACM/ICPC 南京网络赛F题

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

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

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

#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

 

posted @ 2013-09-22 08:50 金海峰 阅读(...) 评论(...) 编辑 收藏