zoukankan      html  css  js  c++  java
  • [模拟赛]五子棋 题解

    Before the Beginning

    转载请将本段放在文章开头显眼处,如有二次创作请标明。

    原文链接:https://www.codein.icu/gm1060/

    前言

    相比于那道恶心的戒指,这道题简直眉目清秀,友善至极,10min打完一发AC。

    题面

    描述

    WHU ACM的队员们迷上了五子棋游戏,他们决定组织一场队内友谊赛以便互相切磋棋艺。 比赛规则是这样的:每位选手都要和其他人进行一场比赛,每场比赛胜者将得到一定的积分,败者不得分,若和棋则双方都不得分。 每位队员都有一个经验值,我们可以认为比赛中经验值较高者获胜,若双方经验值相同则为和棋。 队员们都很聪明,他们会在比赛中不断进步。也就是说,和特定的对手进行比赛后,无论胜负,都会增加一定经验值。 小M作为WHU ACM集训队的队长有资格安排比赛顺序,而同时作为1号选手的他自然希望自己的积分能越高越好。因此,他请你根据相关信息写一个程序来帮助他。

    输入

    输入有多组数据,第一行为一个整数T(1 <= T <= 11),表示数据个数。 每组数据第一行为一个整数N(1 <= N <= 13)表示参赛选手数。 接下来有N行,每行包含N个范围为[0, 1000]的整数,第i 行的第j个数表示选手i与选手j比赛后选手i获得的经验值。 之后N行每行包含N个范围为[0, 10]的整数,第i行的第j个数表示选手i战胜选手j后得到的积分。 最后一行N个范围为[0, 1000]的整数,表示各位选手的初始经验值。

    输出

    输出T行(每行一个数),即小M能获得的最高积分。

    样例

    输入:

    2
    2
    0 1
    1 0
    0 1
    1 0
    1 1
    3
    0 5 2
    0 0 0
    0 0 0
    0 10 1
    1 0 1
    1 0 0
    1 10 5
    

    输出:

    0
    1
    

    解法

    看到数据范围,不难想到是状压DP题目。
    每个人与其他人对战后,经验单调增长,而击败其获得积分不变。
    因此根据贪心,为了让他人的经验尽量小,应该让队长最先与所有人都打完一遍。
    而队长与每个人对战时,对方都是初始经验。
    得出结论后,就是经典的状压DP枚举顺序题目了。
    定义 (f(status)) 为与每个 (1) 位置人打过的最大贡献,考虑转移。
    计算出当前的经验值。
    枚举上一个打的人,减去与之对战的经验值,即为上次对战时的经验值。
    比较双方经验值,判断是否增加贡献。
    按照习惯,打了个记忆化搜索。

    #include <cstdio>
    #include <algorithm>
    #include <ctype.h>
    const int bufSize = 1e6;
    #define DEBUG
    inline char nc()
    {
    #ifdef DEBUG
        return getchar();
    #endif
        static char buf[bufSize], *p1 = buf, *p2 = buf;
        return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, bufSize, stdin), p1 == p2) ? EOF : *p1++;
    }
    inline void read(char *s)
    {
        static char c;
        for (; !isalpha(c); c = nc());
        for (; isalpha(c); c = nc()) *s++ = c;
        *s = '';
    }
    template <typename T>
    inline T read(T &r)
    {
        static char c;
        static int flag;
        flag = 1, r = 0;
        for (c = nc(); !isdigit(c); c = nc()) if (c == '-') flag = -1;
        for (; isdigit(c); c = nc()) r = r * 10 + c - 48;
        return r *= flag;
    }
    const int maxn = 14;
    int T, n;
    int getexp[maxn][maxn], getval[maxn][maxn];
    int sexp[maxn];
    int f[1 << maxn];
    int dfs(int status)
    {
        if (f[status] != -1) return f[status];
        if (status <= 0) return 0;
        int sum = sexp[1], ans = 0;
        for (int i = 1; i <= n; ++i) if ((1 << (i - 1)) & status) sum += getexp[1][i];
        for (int i = 1; i <= n; ++i)
        {
            if ((1 << (i - 1)) & status)
            {
                int nx = status ^ (1 << (i - 1));
                sum -= getexp[1][i];
                if (sum > sexp[i]) ans = std::max(ans, dfs(nx) + getval[1][i]);
                else ans = std::max(ans, dfs(nx));
                sum += getexp[1][i];
            }
        }
        return f[status] = ans;
    }
    int main()
    {
        read(T);
        while (T--)
        {
            read(n);
            for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) read(getexp[i][j]);
            for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) read(getval[i][j]);
            for (int i = 1; i <= n; ++i) read(sexp[i]);
            int maxx = (1 << n) - 1;
            for (int i = 0; i <= maxx; ++i) f[i] = -1;
            printf("%d
    ", dfs(maxx));
        }
        return 0;
    }
    
  • 相关阅读:
    WebService cxf提供接口
    在文件系统的某一个目录中查找某一个字符串
    在notepad++中插件安装的办法
    windows中的oracle12SE后启动的系统服务的列表
    在windows环境初步了解tuxedo
    使用MS VS的命令来编译C++程序
    我所常用的git命令
    使用python对文件中的数值进行累加
    C++中继承关系中的同名隐藏和对策
    用eclipse来制作并使用可执行的jar文件
  • 原文地址:https://www.cnblogs.com/Clouder-Blog/p/gm1060.html
Copyright © 2011-2022 走看看