2018 省选 T1 一双木棋
题目描述
菲菲和牛牛在一块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 一双木棋的更多相关文章
- 洛谷 P4363 [九省联考2018]一双木棋chess 解题报告
P4363 [九省联考2018]一双木棋chess 题目描述 菲菲和牛牛在一块\(n\)行\(m\)列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手. 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落 ...
- 【BZOJ5248】【九省联考2018】一双木棋(搜索,哈希)
[BZOJ5248][九省联考2018]一双木棋(搜索,哈希) 题面 BZOJ Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何 ...
- [BZOJ5248][九省联考2018]一双木棋(连通性DP,对抗搜索)
5248: [2018多省省队联测]一双木棋 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 43 Solved: 34[Submit][Status ...
- 一双木棋(chess)
一双木棋(chess) 题目描述 菲菲和牛牛在一块 nn 行 mm 列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手. 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束.落子的规 ...
- 洛谷P4363 一双木棋 chess
洛谷P4363 一双木棋 chess 省选最水的一道题了. 且看我数个月AC一道题...... 具体是这样的:我们发现这个下了棋的地方一定形成一个锯齿形,那么怎么状态压缩呢? 维护轮廓线! 从左下角出 ...
- noi省选 [九省联考2018]一双木棋题解(状压dp)
比浙江简单多了........ 题目转送:https://www.luogu.org/problemnew/show/P4363 分析: 我们注意到n和m都很小,考虑一下状压dp. 显然,棋子摆成的形 ...
- [九省联考2018] 一双木棋 chess
Description 菲菲和牛牛在一块n 行m 列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手. 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束. 落子的规则是:一个格子可 ...
- B5248 [2018多省省队联测]一双木棋 状压dp
这个题当时划水,得了二十分,现在来整一整. 这个题用状压来压缩边界线,然后通过记忆化搜索进行dp.我们可以观察到,其实每次转移,就是把一个1向左移一位.最后的状态设为0. 这其中还要有一个变量来记录谁 ...
- bzoj 5248: [2018多省省队联测]一双木棋
Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何棋子, 两人轮流在格子上落子,直到填满棋盘时结束.落子的规则是:一个格子可以落子 ...
随机推荐
- 认识Python&基础环境搭建
前言 作为.NET Coder可能.NET Core是现阶段首要学习方向,但是说实在的对Core真的不感冒. 原因有几点: 1.公司项目底层需要的一部分库,Core还不支持. 2.同样的需求,.NET ...
- Jmeter(三十)_TimeShift函数在JSR223中的使用
今天学习一下TimeShift函数在JSR223中的使用方法. 关联之前的一篇时间戳文章:Jmeter(十二)_打印时间戳 首先,创建线程组,在线程组下面创建一个JSR223采样器 选择Groovy语 ...
- 基于HTML5 WebGL实现 json工控风机叶轮旋转
突然有个想法,如果能把一些用到不同的知识点放到同一个界面上,并且放到一个盒子里,这样我如果要看什么东西就可以很直接显示出来,而且这个盒子一定要能打开.我用HT实现了我的想法,代码一百多行,这么少的代码 ...
- Ionic2 下处理 Android 设备下返回按钮的事件
原文发表于我的技术博客 本文分享了 Ionic2 下处理 Android 设备下返回按钮的事件,供参考. 原文发表于我的技术博客 代码中我分享了如何捕捉 Ionic2 项目在 Android 设备下返 ...
- RocketMQ 简单梳理 及 集群部署笔记
一.RocketMQ 基础知识介绍Apache RocketMQ是阿里开源的一款高性能.高吞吐量.队列模型的消息中间件的分布式消息中间件. 上图是一个典型的消息中间件收发消息的模型,RocketMQ也 ...
- Docker容器学习梳理 - 基础知识(1)
Docker是PaaS 提供商 dotCloud 开源的一个基于 LXC 的高级容器引擎,源代码托管在 Github 上, 基于go语言并遵从Apache2.0协议开源.Docker是通过内核虚拟化技 ...
- Spring Cloud :断路器集群监控(Turbine)
一. 简介 上一篇文章我们已经实现了对单个服务实例的监控,当然在实际应用中,单个实例的监控数据没有多大的价值,我们更需要的是一个集群系统的监控信息,这时我们就需要引入Turbine.Turb ...
- bash处理一条命令的步骤
Shell执行一条命令步骤 参考链接: <Learning the bash Shell, 3rd Edition -- 7.3. Command-Line Processing> &l ...
- [Android]记录一次处理app:transformDexArchiveWithExternalLibsDexMergerForDebug错误
第一种情况: Android 目录结构如下: app中build.gradle包含: implementation 'com.squareup.okhttp3:okhttp:3.6.0' implem ...
- SQLserver 进程被死锁问题解决
事务(进程ID xx)与另一个进程被死锁在 锁|通信缓冲区 资源上,并且已被选座死锁牺牲品.请重新运行该事务.Sqlserver 当出现这个错误时,如下图: 解决办法:更改数据库事务隔离级别 alte ...