• 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
    ");
            else
                printf("Jerry404
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    [C/C++]宽字符与控制台程序
    C# 实现屏幕键盘 (SCREENKEYBOARD)
    c#模拟键盘输入
    窗口玻璃特效,半透明窗口,使用DWM实现Aero Glass效果
    DMRS、DRS、SRS、CRS各自作用区别
    LTE的9种传输模式
    在4G通讯技术中什么是ZC根序列,ZC根序列规划的目的和原则是什么?
    為何LTE要先偵測PSS然後再偵測SSS 转自C114
    PSS和SSS用户小区接入的同步过程
    LTE PCI MOD3 规划
  • 原文地址:https://www.cnblogs.com/rainydays/p/3332478.html
Copyright © 2020-2023  润新知