题目描述

菲菲和牛牛在一块n 行m 列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手。 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束。

落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且这个格子的左侧及上方的所有格子内都有棋子。

棋盘的每个格子上,都写有两个非负整数,从上到下第i 行中从左到右第j 列的格 子上的两个整数记作Ai,jA{i,j}Ai,j​ 、Bi,jB{i,j}Bi,j​ 。在游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的Ai,jA{i,j}Ai,j​ 之和,牛牛的得分是所有有白棋的格子上的Bi,jB{i,j}Bi,j​ 的和。

菲菲和牛牛都希望,自己的得分减去对方的得分得到的结果最大。现在他们想知道,在给定的棋盘上,如果双方都采用最优策略且知道对方会采用最优策略,那么,最终的结果如何。 输入输出格式 输入格式:

从文件chess.in 中读入数据。

输入第一行包含两个正整数n;m,保证n;m <= 10。

接下来n 行,每行m 个非负整数,按从上到下从左到右的顺序描述每个格子上的 第一个非负整数:其中第i 行中第j 个数表示Ai,jA_{i,j}Ai,j​ 。

接下来n 行,每行m 个非负整数,按从上到下从左到右的顺序描述每个格子上的 第二个非负整数:其中第i 行中第j 个数表示Bi,jB_{i,j}Bi,j​ 。

输出格式:

输出到文件chess.out 中。

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

分析:

首先,左边、上边所有格子和左边格子、上边格子都填满其实是一样的。

可以通过n/m <=10 想到状压dp

一般大家用的状压dp都是维护之前的几行从左数有几个旗子已经下过。

因为发现,棋盘上下过的地方总是右上角的一个阶梯形状,剩下的总是一个右下角的部分。所以高级的做法是:维护已下过的部分和没有下过的部分的分界线的状态。(1表示横,0表示竖) 状态查看时,从末位向前看,从棋盘左下角划线。

例如样例中,11100是初始状态,00111是最终的状态。

我们可以dfs预处理出所有的状态,C(20,10)种合法状态。接着,我么可以预处理出每个状态的转弯处(0,1交汇处)通过这个转弯处可以下一个棋子,从而转移到下一个状态。

需要注意的是最后work的方法。(又卡了一天)

不能用递推!因为之前的局部最优策略下的最优解可能不是最终局面下的形式。而由于后面的局面“最优解”是通过这个局部策略转移过来的,导致全部错误。

例如:

3 3

9 4 3

6 7 6

4 5 9

0 0 0

0 0 0

0 0 0

错误输出是 29 正解 32

错误的过程是:

9 4 3

0 0 0

4 0 9

正解:

9 0 3

0 7 0

4 0 9

正解中,下棋时会先填满左边一列,而错误解法则是随机的一块中的当前最优解来更新。左上角三个数,错误解法中这就是局部最优解,但是与正解相差甚远。

所以考虑设f[i]表示i状态下,剩下的格子下法中最优解的答案(是一个a-b的差值)

当该a下时,初值f[i]=-inf f[i]=max(f[i],dfs(to,who^1)+a[x][y]); 当该b下时,初值f[i]=inf; f[i]=min(f[i],dfs(to,who^1)-b[x][y]);

加上记忆化搜索即可。(在这里剪掉的是一种局面可能由多种局面下出来的情况,避免再往后推) 100行代码,不开O2照样水过。

总结: 1.应用的算法:状压dp与记忆化搜索结合。 2.注意转移时的方式和顺序。保证最优子结构。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=;
const int M=+;
const int inf=0x3f3f3f3f;
int f[M];
int ret[];
struct node{
int wei[*N][];
int tur;
int zhi;
int size;
}g[M];
int n,m;
int a[N][N],b[N][N];
int cnt=;
int vis[M];
void dfs(int x,int sum,int num1,int num0)
{
if(x==(n+m)+)
{
if(num1==m&&num0==n)
{
g[++cnt].zhi=sum;
}
return;
}
dfs(x+,sum+(<<x-),num1+,num0);
dfs(x+,sum,num1,num0+);
}//0 up 1 right
int dfs2(int hao,int who)
{
if(vis[hao]) return f[hao];
int i=hao;
vis[hao]=;
if(hao==cnt) return ;
if(who&) f[hao]=inf;
else f[hao]=-inf;
for(int i=;i<=g[hao].tur;i++)
{
int h=g[hao].wei[i][];
int l=g[hao].wei[i][];
int x=g[hao].wei[i][];
int y=g[hao].wei[i][];
int to=ret[g[hao].zhi+(<<x-)-(<<y-)];
if(who&) f[hao]=min(f[hao],dfs2(to,-who)-b[h][l]);
else f[hao]=max(f[hao],dfs2(to,-who)+a[h][l]);
}
return f[hao];
}
bool cmp(node a,node b)
{
if(a.size!=b.size) return a.size<b.size;
return a.zhi>b.zhi;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
scanf("%d",&a[i][j]);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
scanf("%d",&b[i][j]);
dfs(,,,);
for(int i=;i<=cnt;i++)
{
int t=g[i].zhi;
int s=;
int last;
int num[];
memset(num,,sizeof num);
while(s!=(n+m))
{
s++;
if(t&) g[i].size+=n-num[];
if(s==) last=(t&);
else{
if(last==&&((t&)==))
{
g[i].wei[++g[i].tur][]=n-num[]+;
g[i].wei[g[i].tur][]=num[]+;
g[i].wei[g[i].tur][]=s-;
g[i].wei[g[i].tur][]=s;
}
last=(t&);
}
num[t&]++;
t>>=;
}
}
sort(g+,g+cnt+,cmp);
for(int i=;i<=cnt;i++)
ret[g[i].zhi]=i;
printf("%d",dfs2(,));
return ;

}

2018 省选 T1 一双木棋的更多相关文章

  1. 洛谷 P4363 [九省联考2018]一双木棋chess 解题报告

    P4363 [九省联考2018]一双木棋chess 题目描述 菲菲和牛牛在一块\(n\)行\(m\)列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手. 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落 ...

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

    [BZOJ5248][九省联考2018]一双木棋(搜索,哈希) 题面 BZOJ Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何 ...

  3. [BZOJ5248][九省联考2018]一双木棋(连通性DP,对抗搜索)

    5248: [2018多省省队联测]一双木棋 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 43  Solved: 34[Submit][Status ...

  4. 一双木棋(chess)

    一双木棋(chess) 题目描述 菲菲和牛牛在一块 nn 行 mm 列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手. 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束.落子的规 ...

  5. 洛谷P4363 一双木棋 chess

    洛谷P4363 一双木棋 chess 省选最水的一道题了. 且看我数个月AC一道题...... 具体是这样的:我们发现这个下了棋的地方一定形成一个锯齿形,那么怎么状态压缩呢? 维护轮廓线! 从左下角出 ...

  6. noi省选 [九省联考2018]一双木棋题解(状压dp)

    比浙江简单多了........ 题目转送:https://www.luogu.org/problemnew/show/P4363 分析: 我们注意到n和m都很小,考虑一下状压dp. 显然,棋子摆成的形 ...

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

    Description 菲菲和牛牛在一块n 行m 列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手. 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束. 落子的规则是:一个格子可 ...

  8. B5248 [2018多省省队联测]一双木棋 状压dp

    这个题当时划水,得了二十分,现在来整一整. 这个题用状压来压缩边界线,然后通过记忆化搜索进行dp.我们可以观察到,其实每次转移,就是把一个1向左移一位.最后的状态设为0. 这其中还要有一个变量来记录谁 ...

  9. bzoj 5248: [2018多省省队联测]一双木棋

    Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何棋子, 两人轮流在格子上落子,直到填满棋盘时结束.落子的规则是:一个格子可以落子 ...

随机推荐

  1. Redis主从复制原理总结

    和Mysql主从复制的原因一样,Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况.为了分担读压力,Redis支持主从复制,Redis的主从结构可以采用一主多从或者级联结构,Redi ...

  2. B. Heaters Div3

    链接 [http://codeforces.com/contest/1066/problem/B] 分析 具体看代码,贪就完事了 代码 #include<bits/stdc++.h> us ...

  3. 结对编程 学习手记ver1.2

        团队成员: 226 高雅智 164刘浩然: 一 结对编程 辛辛苦苦搞了好久的时间,就是没有人家的快,明明算法都差不多,哎~~~ 结对的优势,在于双方互相督促,对于代码能贡献自己的能力,人多力量 ...

  4. week3个人作业

    一.必应词典的bug 必应词典占用资源过多,作为后台软件,必应词典的内存占用是其他的四五倍 适应能力弱,经常与其他软件冲突,兼容性差 二.分析 根据我的分析,团队人数6人左右,计算机大学毕业生,并有专 ...

  5. BUAAMOOC项目终审报告

    工作总结 我们是歪果仁带你灰开发团队.我们开发的项目是北航学堂(MOOC)的android客户端:BUAAMOOC. 目前我们完成了主要功能,包括UI设计,视频播放,视频下载,学习进度,个人信息等功能 ...

  6. 《Linux内核设计与实现》读书笔记六

    第4章 进程调度35 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间,进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统.只有通过调度程序的合理调度,系统资源才能最 ...

  7. 团队作业:SRS文档-飞机大战

    本实验为团队合作项目作业的一部分:SRS文档-飞机大战 项目分工:SRS文档项目为梁JM负责完成 实验要求: 3.SRS文档(第二周,截止5月31日)              要求对所选项目进行用例 ...

  8. java.lang.Exception: No tests found matching Method tes(com.bw.test.Testrefiect) from org.junit.vintage.engine.descriptor.RunnerRequest@3bfdc050 at org.junit.internal.requests.FilterRequest.getRunner

    junit   方法  没有加上注解  @Test java.lang.Exception: No tests found matching Method tes(com.bw.test.Testre ...

  9. MySQL基础~~编程语法

    常量 数值 字符串:单引号或者双引号括起来.包括普通字符串或者日期格式的字符串. 布尔值:false(FALSE)对应数字值为0.true(TRUE)对应数字值为1. NULL:可以参考http:// ...

  10. Installing and removing VNC Connect | Red Hat | VNC Connect

    https://www.realvnc.com/en/connect/docs/redhat-install-remove.html 此软件会和TigerVNC(Server)或者X11VNC Ser ...