题目描述

菲菲和牛牛在一块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. open-falcon ---客户机agent操作

    open-falcon的agent用于采集机器负载监控指标,比如cpu.idle.load.1min.disk.io.util等等,每隔60秒push给Transfer.agent与Transfer建 ...

  2. Python数据类型-7

    什么数据类型. int 1,2,3用于计算. bool:True,False,用户判断. str:存储少量数据,进行操作 'fjdsal' '二哥','`13243','fdshklj' '战三,李四 ...

  3. bootstrap面试题

    1.你能描述一下渐进增强和优雅降级之间的不同吗? 优雅降级:Web站点在所有新式浏览器中都能正常工作,如果用户使用的是老式浏览器,则代码会检查以确认它们是否能正常工作.由于IE独特的盒模型布局问题,针 ...

  4. 牛客小白月赛6-E对弈-简单搜索

    https://www.nowcoder.com/acm/contest/136/E 我搜索很差啊,看了学长代码,自己在下面手敲了一遍,感觉学长的极其精巧,把我繁琐的搜索步骤给简化了不少 其实本题想法 ...

  5. 四则运算APP

    1)   N (Need 需求) 用户基本需求:随机生成四则运算,能自动判定对错,答错时能提示正确答案! 在这个基础上,我的创意: 多用户模式,能记录用户的答题情况(登陆功能) 分级挑战,按照不同的水 ...

  6. C# 中颜色和名称样式对照表

    WPF中的画刷也一样适用 System.Windows.Media.Brushes.名称 (如:System.Windows.Media.Brushes.AliceBlue) :first-child ...

  7. h5定位geolaction无法调试解决方法

    昨天接到一个在h5获取经纬度的需求,看了文档后,代码其实很简单,但在浏览器上调试就比较蛋疼了... 代码: function successfulCallback(position) { consol ...

  8. PAT 1041 考试座位号

    https://pintia.cn/problem-sets/994805260223102976/problems/994805281567916032 每个PAT考生在参加考试时都会被分配两个座位 ...

  9. Win2012r2 以及win2016 安装.NET3.5

    自从微软的内核 6.2以上的版本之后 win2012 win2016 已经自带了 .net4.0的版本 但是很多应用还需要.net 3.5的版本,虽然微软的安装盘里面有 .net 3.5的安装文件,但 ...

  10. python 深入浅出装饰器(decorator)--举的例子关于星级争霸2(starcraft2)

    其实早就想写一篇深入浅出装饰器的文章,苦于一直没有找到很好的例子描述,自己除了在写api参数检测和日志打印的时候用到以外,其他地方也没有什么重度使用所以一直没有写. 我不会讲解装饰器的理论,还有各种基 ...