[2018九省联考]一双木棋

Description

菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手。棋局开始时,棋盘上没有任何棋子,

两人轮流在格子上落子,直到填满棋盘时结束。落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且

这个格子的左侧及上方的所有格子内都有棋子。

棋盘的每个格子上,都写有两个非负整数,从上到下第i行中从左到右第j列的格子上的两个整数记作Aij、Bij。在

游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的Aij之和,牛牛的得分是所

有有白棋的格子上的Bij的和。

菲菲和牛牛都希望,自己的得分减去对方的得分得到的结果最大。现在他们想知道,在给定的棋盘上,如果双方都

采用最优策略且知道对方会采用最优策略,那么,最终的结果如何

Input

第一行包含两个正整数n,m,保证n,m≤10。

接下来n行,每行m个非负整数,按从上到下从左到右的顺序描述每个格子上的

第一个非负整数:其中第i行中第j个数表示Aij。

接下来n行,每行m个非负整数,按从上到下从左到右的顺序描述每个格子上的

第二个非负整数:其中第i行中第j个数表示Bij

n, m ≤ 10 , Aij, Bij ≤ 100000

Output

输出一个整数,表示菲菲的得分减去牛牛的得分的结果。

Sample Input

2 3

2 7 3

9 1 2

3 7 2

2 3 1

Sample Output

2

解题思路:

考虑可行的状态只有C(10, 20)种,因为每一行向右填的棋子数是不严格递减的,然后就把每一行向右填了多少棋子作为状态进行DP,考虑要求的是一个Sa-Sb,那么对于这个答案来言,A取一个格子能获得的贡献是a(i, j) + b(i, j),这样的话答案就是A最多能取到的贡献 - sum(b(i, j)),所以状态定义为f[now][s]表示棋盘在now状态下,此时s落子时A最大能取多少贡献,s = 0表示A落子,s = 1表示B落子,转移yy一下即可..

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
template <class T>
inline void read(T &x){
    int f = 0, ch = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - ‘0‘;
    if(f) x = -x;
}
int a[20][20], b[20][20], n, m, sa, sb, tot;
struct Point{
    int a[20];
    inline Point(){ memset(a, 0, sizeof(a)); }
    inline ull get(){
        ull ans = 0;
        for(int i = 1; i <= n; i++) ans = ans * 233 + a[i];
        return ans;
    }
};
map<ull, int> f[2], vis[2];
inline int dfs(Point now, int s){
    ull ss = now.get();
    if(vis[s][ss]) return f[s][ss];
    int flag = 0; vis[s][ss] = 1, f[s][ss] = s ? 0 : inf;
    for(register int i = 1; i <= n; i++)
        if((now.a[i] < now.a[i-1] || i == 1) && now.a[i] < m){
            flag = 1; Point nxt = now; nxt.a[i]++;
            int val = a[i][now.a[i]+1] + b[i][now.a[i]+1];
            if(!s)
                f[s][ss] = min(f[s][ss], dfs(nxt, s ^ 1));
            else
                f[s][ss] = max(f[s][ss], val + dfs(nxt, s ^ 1));
        }
    return !flag ? 0 : f[s][ss];
}
int main(){
    read(n), read(m);
    for(register int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) read(a[i][j]);
    for(register int i = 1; i <= n; i++)
        for(register int j = 1; j <= m; j++)
            read(b[i][j]), sb += b[i][j];
    Point fi; cout << dfs(fi, 1) - sb << endl;
    return 0;
}

萌萌哒的代码

原文地址:https://www.cnblogs.com/mangoyang/p/8733509.html

时间: 2024-08-30 12:14:26

[2018九省联考]一双木棋的相关文章

[BZOJ5248] 2018九省联考 D1T1 一双木棋 | 博弈论 状压DP

题面 菲菲和牛牛在一块\(n\)行\(m\)列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手. 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束. 落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且这个格子的左侧及上方的所有格子内都有棋子. 棋盘的每个格子上,都写有两个非负整数,从上到下第i 行中从左到右第j 列的格 子上的两个整数记作\(A_{i, j}\).\(B_{i, j}\).在游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的\

【BZOJ5248】【九省联考2018】一双木棋(搜索,哈希)

[BZOJ5248][九省联考2018]一双木棋(搜索,哈希) 题面 BZOJ Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何棋子, 两人轮流在格子上落子,直到填满棋盘时结束.落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且 这个格子的左侧及上方的所有格子内都有棋子. 棋盘的每个格子上,都写有两个非负整数,从上到下第i行中从左到右第j列的格子上的两个整数记作Aij.Bij.在 游戏结束后,菲菲和牛牛会分别计算自己

[luogu] P4364 [九省联考2018]IIIDX(贪心)

P4364 [九省联考2018]IIIDX 题目背景 Osu 听过没?那是Konano 最喜欢的一款音乐游戏,而他的梦想就是有一天自己也能做个独特酷炫的音乐游戏.现在,他在世界知名游戏公司KONMAI 内工作,离他的梦想也越来越近了. 这款音乐游戏内一般都包含了许多歌曲,歌曲越多,玩家越不易玩腻.同时,为了使玩家在游戏上氪更多的金钱花更多的时间,游戏一开始一般都不会将所有曲目公开,有些曲目你需要通关某首特定歌曲才会解锁,而且越晚解锁的曲目难度越高. 题目描述 这一天,Konano 接到了一个任务

九省联考 2018 游记

Day0:乘火车到了上海.明天就是激动人心的比赛啦 深夜和室友看<我在七年后等你>.这真是一款不错的手游,让人印象深刻啊 Day1:迷迷糊糊到了学校.编程环境是Win7?不太习惯啊. T1:一眼状压dp题. T2:肯定可以建成一棵树,然后直接贪心?不对啊,T2不应该这么水啊(开始怀疑) T3:乍一看怎么一点思路没有啊. 8:40~11:10:持续思考T3中. 11:10:终于有思路了!如果直接NTT向上dp的话,因为链的情况复杂度会不对,所以似乎可以树剖!用线段树分治和NTT处理重链上的dp!

[BZOJ5248][九省联考2018]双木棋chess

bzoj luogu sol 首先,要保证一个格子的左边和上方都放满了棋子,就需要这个点的左上方那个矩形都放满了棋子. 这样放旗子状态就会是一个自左下至右上的轮廓线. 状态数? 跟\(yyb,ppl\)讨论了一下状态数理论上应该是\(C_{20}^{10}\)啊. 然而... #include<cstdio> #include<algorithm> using namespace std; int n,m,a[20],tot; void dfs(int u) { if (u==n+

[九省联考 2018]一双木棋chess

Description 题库链接 给出一个 \(n\times m\) 的棋盘,棋盘的每个格子有两个权值 \(A,B\) . Alice 和 Bob 轮流操作在棋盘上放棋子,一个格子能放棋子的前提条件是这个格子的左侧和上侧均放了棋子.对于 Alice 放棋子的格子,能获得该格子的 \(A\) 的权值:对于 Bob 放棋子的格子,能获得该格子的 \(B\) 的权值. Alice 想最大化得分差, Bob 想最小化得分差,求最后得分差. \(1\leq n,m\leq 10\) Solution 比

P4363 [九省联考2018]一双木棋

题面 这种搜索要把后继状态都跑出来之后取Min/Max 也就是回溯的时候进行操作 记得用hash进行记忆化(用map不开O2会TLE) #include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<map> #define rg register #de

P4363 [九省联考2018]一双木棋chess(对抗搜索+记忆化搜索)

传送门 这对抗搜索是个啥玩意儿…… 首先可以发现每一行的棋子数都不小于下一行,且局面可由每一行的棋子数唯一表示,那么用一个m+1进制数来表示当前局面,用longlong存,开map记忆化搜索 然后时间复杂度的问题,rqy这样说的 然后这个对抗搜索的话……个人理解就是因为要最大化分值的差,所以在一个人下棋的时候令他得分最大,另一个人得分最小 1 //minamoto 2 #include<cstdio> 3 #include<iostream> 4 #include<map&g

p4363 [九省联考2018]一双木棋chess

传送门 分析 我们用0表示向右,1表示向上 于是可以得到一条江棋盘分为两块的线 直接dp即可 代码 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cctype> #include<cmath> #include<cstdlib> #include<cti