[模拟赛]五子棋 题解
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枚举顺序题目了。
定义 为与每个 位置人打过的最大贡献,考虑转移。
计算出当前的经验值。
枚举上一个打的人,减去与之对战的经验值,即为上次对战时的经验值。
比较双方经验值,判断是否增加贡献。
按照习惯,打了个记忆化搜索。
#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 = '\0'; } 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\n", dfs(maxx)); } return 0; }
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 对象命名为何需要避免'-er'和'-or'后缀
· SQL Server如何跟踪自动统计信息更新?
· AI与.NET技术实操系列:使用Catalyst进行自然语言处理
· 分享一个我遇到过的“量子力学”级别的BUG。
· Linux系列:如何调试 malloc 的底层源码
· C# 中比较实用的关键字,基础高频面试题!
· .NET 10 Preview 2 增强了 Blazor 和.NET MAUI
· Ollama系列05:Ollama API 使用指南
· 为什么AI教师难以实现
· 如何让低于1B参数的小型语言模型实现 100% 的准确率