题面

题面

题解

通过观察,我们可以发现如下性质:

  • 可以看做是2个人在不断移动空格,只是2个人能移动的边不同
  • 一个位置不会被重复经过 : 根据题目要求,因为是按黑白轮流走,所以不可能重复经过一个点,不然就变成一个人连续走2次了
  • 原图是一个二分图 : 也是由按黑白轮流走这个要求得到的

    因此我们对原图按照与原点的距离进行黑白染色,再跑二分图博弈即可。
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 45
#define ac 5000 int n, m, sx, sy, all;
int id[AC][AC], ans[ac], link[ac];
int a[6] = {-1, 1, 0, 0}, b[6] = {0, 0, -1, 1};
bool can[AC][AC], z[ac], vis[ac];
char s[AC][AC]; struct node{int x, y;}back[ac]; inline int read()
{
int x = 0;char c = getchar();
while(c > '9' || c < '0') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
} bool check(int x, int y)//起点是黑色
{
int tmp = abs(x - sx) + abs(y - sy);
if((tmp & 1) && s[x][y] == 'O') return 1;//相距奇数格,则为白格,需要白色
else if(!(tmp & 1) && s[x][y] == 'X') return 1;
else if(s[x][y] == '.') return 1;
return 0;
} bool dfs(int x)
{
for(R i = 0; i < 4; i ++)
{
int xx = back[x].x + a[i], yy = back[x].y + b[i], ID = id[xx][yy];
if(xx <= 0 || yy <= 0 || xx > n || yy > m) continue;
if(!can[xx][yy] || vis[ID]) continue;
vis[ID] = true;
if(!link[ID] || dfs(link[ID]))
{
link[ID] = x, link[x] = ID;
return true;
}
}
return false;
} void cal()
{
int tmp = (sx + sy) % 2;
for(R i = 1; i <= all; i ++)
{
int x = back[i].x, y = back[i].y;
if((x + y) % 2 != tmp || !can[x][y]) continue;//和为奇数则在T集合
memset(vis, 0, sizeof(vis)), dfs(i);
}
} bool dfs1(int x)
{
for(R i = 0; i < 4; i ++)
{
int xx = back[x].x + a[i], yy = back[x].y + b[i], ID = id[xx][yy];
if(xx <= 0 || yy <= 0 || xx > n || yy > m) continue;
if(!can[xx][yy] || vis[ID]) continue;
vis[ID] = true;
if(!link[ID] || dfs(link[ID])) return true;
}
return false;
} void pre()
{
n = read(), m = read(), all = n * m;
int tmp1 = 1, tmp2 = 2;
for(R i = 1; i <= n; i ++)
{
scanf("%s", s[i] + 1);
for(R j = 1; j <= m; j ++)
{
if(s[i][j] == '.') sx = i, sy = j;
if((i + j) & 1) id[i][j] = tmp2, back[tmp2] = (node){i, j}, tmp2 += 2;
else id[i][j] = tmp1, back[tmp1] = (node){i, j}, tmp1 += 2;
}
}
for(R i = 1; i <= n; i ++)
for(R j = 1; j <= m; j ++) can[i][j] = check(i, j);
} void check_()
{
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++) printf("%d ", can[i][j]);
printf("\n");
} for(R i = 1; i <= n; i ++)
{
for(R j = 1; j <= m; j ++) printf("%d ", link[id[i][j]]);
printf("\n");
}
} void work()
{
int T = read() << 1, x, y, ID, tmp; bool done;
for(R i = 0; i <= T; i ++)
{
for(R j = 1; j <= all; j ++) z[j] = 0;
if(i) x = read(), y = read(), ID = id[x][y];
else x = sx, y = sy, ID = id[x][y];
can[x][y] = 0;//这个要在一开始就修改
if(!link[ID]) continue;//搜S/T集合中有没有可到达的同侧未匹配点来取代它,因为直接搜不太方便,所以直接搜对面的匹配点是否可以找到增广路
memset(vis, 0, sizeof(vis));
done = dfs(link[ID]);//找到了说明这个点不是必须点
tmp = link[ID];//所以搜这个点的匹配点是否可以找到对面的一个未匹配点(反向增广)
if(done) link[ID] = 0;//清空这个点的匹配,因为这个点已经到过了,所以就不能到达了,如果已经匹配上了就不能改了
else if(!done) link[ID] = link[tmp] = 0, ans[i] = true;//没有可取代点就先手必胜
}
/*for(R i = 0; i <= T; i ++) printf("%d ", ans[i]);
printf("\n");*/
int rnt = 0;
for(R i = 0; i <= T; i += 2)
if(ans[i] == 1 && ans[i + 1] == 1) ++ rnt;
printf("%d\n", rnt);
for(R i = 0; i <= T; i += 2)
if(ans[i] == 1 && ans[i + 1] == 1) printf("%d\n", (i + 2) >> 1);
} int main()
{
// freopen("in.in", "r", stdin);
pre();
cal();
work();
// fclose(stdin);
return 0;
}

[NOI2011]兔兔与蛋蛋游戏 二分图博弈的更多相关文章

  1. [luogu1971 NOI2011] 兔兔与蛋蛋游戏 (二分图博弈)

    传送门 Solution 补一篇二分图博弈 这个博客写的很详细qwq: https://www.cnblogs.com/maijing/p/4703094.html Code //By Menteur ...

  2. BZOJ.2437.[NOI2011]兔兔与蛋蛋游戏(二分图博弈 匈牙利)

    题目链接 首先空格的移动等价于棋子在黑白格交替移动(设起点移向白格就是黑色),且不会走到到起点距离为奇数的黑格.到起点距离为偶数的白格(删掉就行了),且不会重复走一个格子. (然后策略就同上题了,只不 ...

  3. [JSOI2009]游戏 二分图博弈

    题面 题面 题解 二分图博弈的模板题,只要会二分图博弈就可以做了,可以当做板子打. 根据二分图博弈,如果一个点x在某种方案中不属于最大匹配,那么这是一个先手必败点. 因为对方先手,因此我们就是要找这样 ...

  4. BZOJ 1443 游戏(二分图博弈)

    新知识get. 一类博弈问题,基于以下条件: 1.博弈者人数为两人,双方轮流进行决策.2.博弈状态(对应点)可分为两类(状态空间可分为两个集合),对应二分图两边(X集和Y集).任意合法的决策(对应边) ...

  5. luogu4055 游戏 (二分图博弈)

    考虑对非障碍的点黑白染色然后做二分图最大匹配,那么有结论,先手必胜当且仅当不是完美匹配,而且可以放的点是那些可以不匹配的点 从非匹配点开始走,后手只能走到匹配点,于是先手就可以走匹配边.由于不能走走过 ...

  6. [模板] 二分图博弈 && BZOJ2463:[中山市选2009]谁能赢呢?

    二分图博弈 from BZOJ 1443 游戏(二分图博弈) - free-loop - 博客园 定义 1.博弈者人数为两人,双方轮流进行决策. 2.博弈状态(对应点)可分为两类(状态空间可分为两个集 ...

  7. 【BZOJ 2437】 2437: [Noi2011]兔兔与蛋蛋 (博弈+二分图匹配**)

    未经博主同意不得转载 2437: [Noi2011]兔兔与蛋蛋 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 693  Solved: 442 Des ...

  8. bzoj 2437[Noi2011]兔兔与蛋蛋 黑白染色二分图+博弈+匈牙利新姿势

    noi2011 兔兔与蛋蛋 题目大意 直接看原题吧 就是\(n*m\)的格子上有一些白棋和一些黑棋和唯一一个空格 兔兔先手,蛋蛋后手 兔兔要把与空格相邻的其中一个白棋移到空格里 蛋蛋要把与空格相邻的其 ...

  9. BZOJ2437 NOI2011兔兔与蛋蛋(二分图匹配+博弈)

    首先将棋盘黑白染色,不妨令空格处为黑色.那么移动奇数次后空格一定处于白色格子,偶数次后空格一定处于黑色格子.所以若有某个格子的棋子颜色与棋盘颜色不同,这个棋子就是没有用的.并且空格与某棋子交换后,棋子 ...

随机推荐

  1. python 布尔值 bool( ) 与逻辑运算符

    逻辑运算符 not and or 运算符优先级 not > and >or printer(x or y)  x为非零,则返回x,否则返回y print(1 or 2) print(3 o ...

  2. 【linux报错】-bash: xhost: command not found

    参考自:http://blog.csdn.net/csdnones/article/details/51513163,感谢原作者解决了我的问题. 执行xhost +,报以下错误,原因是因未没有安装相关 ...

  3. pg执行计划

  4. activeX 打包

    原文 http://www.docin.com/p-409284488.html CAB打包文档说明 文档目的 本文档的目的在于说明将ocx和dll以及相关的文件打包成一个CAB包,以便在网页下调用o ...

  5. Appium + java截图方法

    public static void takeScreenShot(AndroidDriver<WebElement> driver) { File screenShotFile = dr ...

  6. discuz修改附件出售用其他积分,与帖子不一样

    现实中我遇到了这种情况,一个资源可以用两种积分购买,于是我决定用售卖贴和出售附件的方式,附件内容与贴内隐藏内容是一样的,但目前discuz的出售主题和附件使用的是同一种积分,有了此修改 1.首先是显示 ...

  7. selenium 列表循环定位方法。

    话不多说,直接上代码. 就是循环第一层,然后拼接,然后继续循环,继续屏接,任你多少层都不是问题. def c_select(self, values, text): """ ...

  8. cinder的组件

    跟nova相似,cinder也有很多组件,每个组件负责各自的业务,然后共同协作完成volume的管理.组件之间的通信方式与nova个组件之间的通信方式相同,都是通过消息队列进行通信. cinder-a ...

  9. 4.hive的外部表和内部表

    1.外部表和内部表区别 创建表时:创建内部表时,会将数据移动到数据仓库指向的路径:若创建外部表,仅记录数据所在的路径, 不对数据的位置做任何改变. 删除表时:在删除表的时候,内部表的元数据和数据会被一 ...

  10. 第八次作业psp

    psp 进度条 代码累积折线图 博文累积折线图 psp饼状图