洛谷 P4363 [九省联考2018]一双木棋chess 解题报告
P4363 [九省联考2018]一双木棋chess
题目描述
菲菲和牛牛在一块\(n\)行\(m\)列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手。 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束。
落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且这个格子的左侧及上方的所有格子内都有棋子。
棋盘的每个格子上,都写有两个非负整数,从上到下第\(i\)行中从左到右第\(j\)列的格子上的两个整数记作\(A_{i,j},B_{i,j}\) 。在游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的\(A_{i,j}\)之和,牛牛的得分是所有有白棋的格子上的\(B_{i,j}\)的和。
菲菲和牛牛都希望,自己的得分减去对方的得分得到的结果最大。现在他们想知道,在给定的棋盘上,如果双方都采用最优策略且知道对方会采用最优策略,那么,最终的结果如何。
输入输出格式
输入格式:
输入第一行包含两个正整数\(n,m\),保证\(n,m<=10\)。
接下来\(n\)行,每行\(m\)个非负整数,按从上到下从左到右的顺序描述每个格子上的 第一个非负整数:其中第\(i\)行中第\(j\)个数表示\(A_{i,j}\) 。
接下来\(n\)行,每行\(m\)个非负整数,按从上到下从左到右的顺序描述每个格子上的 第二个非负整数:其中第\(i\)行中第\(j\)个数表示\(B_{i,j}\) 。
输出格式:
输出一个整数,表示菲菲的得分减去牛牛的得分的结果。
说明:

也算是第一次做这样的博弈吧,省选划水的时候没做过状压也没做过博弈。好不容易YY出了\(n+m\)轮廓线处理的方法却不清楚怎么确定最优策略。结果15分的分类讨论分居然因为读入把A,B一起读了而爆0。。
先看看最优策略如何确定的:如果双方都采用最优策略且知道对方会采用最优策略。
由此我们得,我们要使用最优策略,首先要知道对方的最优策略,然后才能确定自己的最优策略。
但是如果我们只考虑前面的已经做的状态,是无法得知最优策略的。
这时候我们反其道而行之,把当前一步可以到达的局面看成一个子问题。这个子问题已经产生了答案,它是一个规模缩小版的但已经处理完了每一步的一个游戏。我们这一步可以进入这个子问题,但进入的入口并不唯一,我们对这个不唯一进行决策,找到对自己而言的局面最大化进入。而这个子问题的最小规模又是唯一确定的,也就是最后一步。所以我们的思路是,先通过记忆化搜索进入最后一步,然后像做树形DP那样在对搜索树进行回溯的时候更新答案。
对于两个人的具体策略而言,我们不妨把\(score_a-score_b\)压入转移方程,则\(A\)的目的是求\(score_a-score_b\)极大化,而\(B\)的目的是求\(score_a-score_b\)极小化,这就是\(max-min\)对抗式搜索模型。
我们再来分析一下每一步的状态:一个格子可以落子当且仅当这个格子内没有棋子且这个格子的左侧及上方的所有格子内都有棋子,题目中这样一句话给了我们一个轮廓线描述状态的启示,我们只能在这样的轮廓线上进行,用0描述竖着的轮廓线,用1描述横着的轮廓线,则状态可以被长为\(n+m\)的轮廓线唯一的表示
画图举个例子

轮廓线为1001101
当进行状态转移时,我们模拟一下可以发现,当某位上为1而这一位的更高一位上为0时,当我们把这两位取反就是把轮廓线向外扩张了一个。用轮廓线确定坐标也不难,我们从低位开始枚举,对每一位的0或1决定如何移动当前对应坐标即可
Code:
#include <cstdio>
const int inf=0x3f3f3f3f;
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int n,m,a[12][12],b[12][12],dp[1048578],used[1048578];
void init()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&b[i][j]);
}
int dfs(int s,int who)
{
if(used[s])
return dp[s];
used[s]=1;
dp[s]=who?-inf:inf;
int x=1,y=m,tmp;
for(int i=0;i<n+m-1;i++)
{
if(((s>>i)&1)&&!((s>>i+1)&1))
{
tmp=s^(3<<i);
if(who)
dp[s]=max(dp[s],dfs(tmp,who^1)+a[x][y]);
else
dp[s]=min(dp[s],dfs(tmp,who^1)-b[x][y]);
}
if((s>>i)&1) y--;
else x++;
}
return dp[s];
}
int main()
{
init();
used[(1<<n+m)-(1<<n)]=1;
printf("%d\n",dfs((1<<m)-1,1));
return 0;
}
2018.7.6
洛谷 P4363 [九省联考2018]一双木棋chess 解题报告的更多相关文章
- 洛谷 P4363 [九省联考2018]一双木棋chess 题解
题目链接:https://www.luogu.org/problemnew/show/P4363 分析: 首先博弈,然后考虑棋盘的规则,因为一个子在落下时它的上面和左面都已经没有空位了,所以棋子的右下 ...
- 洛谷P4363 [九省联考2018]一双木棋chess 【状压dp】
题目 菲菲和牛牛在一块n 行m 列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手. 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束. 落子的规则是:一个格子可以落子当且仅当这个 ...
- luogu P4363 [九省联考2018]一双木棋chess
传送门 对抗搜索都不会,我真是菜死了qwq 首先根据题目条件,可以发现从上到下每一行的棋子数是单调不增的,然后n m都比较小,如果把状态搜出来,可以发现合法状态并不多,所以可以用一个11进制数表示状态 ...
- 【题解】Luogu P4363 [九省联考2018]一双木棋chess
原题传送门 这道题珂以轮廓线dp解决 经过推导,我们珂以发现下一行的棋子比上一行的棋子少(或等于),而且每一行中的棋子都是从左向右依次排列(从头开始,中间没有空隙) 所以每下完一步棋,棋盘的一部分是有 ...
- P4363 [九省联考2018]一双木棋chess
思路 容易发现只能在轮廓线的拐点处落子,所以棋盘的状态可以用一个n+m长度的二进制数表示 转移就是10变成01 代码 #include <cstdio> #include <algo ...
- P4363 [九省联考2018]一双木棋chess(对抗搜索+记忆化搜索)
传送门 这对抗搜索是个啥玩意儿…… 首先可以发现每一行的棋子数都不小于下一行,且局面可由每一行的棋子数唯一表示,那么用一个m+1进制数来表示当前局面,用longlong存,开map记忆化搜索 然后时间 ...
- BZOJ.5248.[九省联考2018]一双木棋chess(对抗搜索 记忆化)
BZOJ 洛谷P4363 [Update] 19.2.9 重做了遍,感觉之前写的有点扯= = 首先棋子的放置情况是阶梯状的. 其次,无论已经放棋子的格子上哪些是黑棋子哪些是白棋子,之前得分如何,两人在 ...
- [九省联考2018]一双木棋chess——搜索+哈希
题目:bzoj5248 https://www.lydsy.com/JudgeOnline/problem.php?id=5248 洛谷P4363 https://www.luogu.org/prob ...
- P4363 [九省联考2018]一双木棋
题面 这种搜索要把后继状态都跑出来之后取Min/Max 也就是回溯的时候进行操作 记得用hash进行记忆化(用map不开O2会TLE) #include<iostream> #includ ...
随机推荐
- 脚本处理iOS的Crash日志
背景 当我们打包app时,可以选择生成对应的符号表,其保存 16 进制函数地址映射信息,通过给定的函数起始地址和偏移量,可以对应函数具体信息以供分析. 所以我们拿到测试给的闪退日志(.crash)时, ...
- Netty源码分析第2章(NioEventLoop)---->第1节: NioEventLoopGroup之创建线程执行器
Netty源码分析第二章: NioEventLoop 概述: 通过上一章的学习, 我们了解了Server启动的大致流程, 有很多组件与模块并没有细讲, 从这个章开始, 我们开始详细剖析netty的各个 ...
- nodejs 搭建自己的简易缓存cache管理模块
http://www.infoq.com/cn/articles/built-cache-management-module-in-nodejs/ 为什么要搭建自己的缓存管理模块? 这个问题其实也是在 ...
- 第10讲:利用SQL语言实现关系代数操作
一.实现并.交.差运算 1. 基本语法形式:子查询 [union [all] | intersect [all] | except [all] 子查询] ①意义:将关系代数中的∪.∩.- 分别用uni ...
- Oracle和MySQL插入时获取主键
这里只写selectKey方法的 一,Oracle数据库中的写法 order="BEFORE"因为oracle中需要先从序列获取值,然后将值作为主键插入到数据库中 <sele ...
- 渡过OO的死劫,了解规格的意义——OO第三次博客总结
当熬过了一次次黑暗,迎接我们的却是被扣的惨不忍睹的JSF ┭┮﹏┭┮ 一.总结调研 规格的历史 传统科学的特点是发现世界,而软件的特点是构造世界.软件的最底层就是0,1,两个离散的值.程序设计语言的三 ...
- class 3 求数组中的最大值(单元测试)
1.问题引出: int Largest(int list[], int length) { int i,max; ; i < (length – ); i ++ ) { if(list[i] & ...
- Spring笔记③--spring的命名空间
p:命名空间: xmlns:p="http://www.springframework.org/schema/p" 作用:简化在xml配置bean的属性 在<bean> ...
- Java 多线程之:偏向锁,轻量级锁,重量级锁
一:java多线程互斥,和java多线程引入偏向锁和轻量级锁的原因? --->synchronized的重量级别的锁,就是在线程运行到该代码块的时候,让程序的运行级别从用户态切换到内核态,把所有 ...
- jquery easyui datagrid getSelected getChecked获取选择行数据(勾选)数据
要想获得上图所选取的元素只能用getChecked getSelected不能进行多个选择,只能单选 /* getSelected取得选中的数据,否则为null */ var user=$(" ...