博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ 1443 游戏(二分图博弈)
阅读量:5174 次
发布时间:2019-06-13

本文共 2500 字,大约阅读时间需要 8 分钟。

新知识get。

一类博弈问题,基于以下条件:

1.博弈者人数为两人,双方轮流进行决策。

2.博弈状态(对应点)可分为两类(状态空间可分为两个集合),对应二分图两边(X集和Y集)。任意合法的决策(对应边)使状态从一类跳转到另一类。(正是由于这个性质使得问题可以用二分图描述)
3.不可以转移至已访问的状态。(不可重复访问点)
4.无法转移者判负。

这类问题相当于从二分图指定起点开始轮流移动,不可重复访问点,无法移动判负 。

现在问题变为从二分图指定起点开始轮流移动,不可重复访问点,无法移动判负。

不妨设起点在二分图的X集中,那么先手只能从X集移动到Y集,后手只能从Y集移动到X集。一次游戏过程对应一条路径 。若最后停留在X集且无法移动则先手负,停留在Y集则后手负。
考虑该二分图的某个最大匹配。(注意可能存在多个匹配相同的最大匹配)
若起点s∈X不属于该最大匹配。则先手所转移到的点y∈Y一定属于最大匹配(否则s-y是一个匹配,与最大匹配矛盾)。后手沿着最大匹配的边走即可,终点t(指无法从t再走一步)一定不可能在Y集中(否则,若t在Y集中,s-...-t为一增广路,与最大匹配矛盾)。因此先手必败,后手必胜。
若起点s∈X属于该最大匹配。则将s从图中删除,再求图的最大匹配。若最大匹配数不变,则s还是不属于某最大匹配,先手必败。否则该图的任意最大匹配都包含s,则先手沿着最大匹配的边走即可,根据上面的分析,先手必胜。

 

也就是说题目中按棋盘黑白染色构建二分图后,必胜点就是二分图中的所有的最大匹配非必要点。不能直接枚举。会超时。

首先,不构成最大匹配的点一定是非必要点。

其次,对不构成最大匹配的点出发走交错轨可以求出其他的非必要点。

 

#include
int n,m;char s[128][128];int xs[]={-1,0,1,0};int ys[]={
0,-1,0,1};int px[128][128],py[128][128],d[128][128],now,v[128][128],ed[128][128];bool dfs(int x,int y){ d[x][y]=now; if(px[x][y]&&d[px[x][y]][py[x][y]]!=now)return dfs(px[x][y],py[x][y]); for(int i=0;i<4;i++){ int x1=x+xs[i],y1=y+ys[i]; if(d[x1][y1]!=now&&s[x1][y1]=='.'&&!px[x1][y1]){ px[x][y]=x1;py[x][y]=y1; px[x1][y1]=x;py[x1][y1]=y; return 1; } } for(int i=0;i<4;i++){ int x1=x+xs[i],y1=y+ys[i]; if(d[x1][y1]!=now&&s[x1][y1]=='.'&&dfs(x1,y1)){ px[x][y]=x1;py[x][y]=y1; px[x1][y1]=x;py[x1][y1]=y; return 1; } } return 0;}void dfs2(int x,int y){ if(ed[x][y]||s[x][y]!='.')return; ed[x][y]=1; v[x][y]=1; for(int i=0;i<4;i++){ int x1=x+xs[i],y1=y+ys[i]; if(px[x1][y1])dfs2(px[x1][y1],py[x1][y1]); }}int main(){
int a=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%s",s[i]+1); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(s[i][j]=='.'&&!px[i][j]){ ++now; a+=dfs(i,j); } } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(s[i][j]=='.'&&!px[i][j])v[i][j]=1; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(s[i][j]=='.'&&!px[i][j])dfs2(i,j); } } bool win=0; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(v[i][j])win=1; } } puts(win?"WIN":"LOSE"); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(v[i][j])printf("%d %d\n",i,j); } } return 0;}
View Code

 

转载于:https://www.cnblogs.com/lishiyao/p/6581342.html

你可能感兴趣的文章
django orm 数据查询详解
查看>>
JarvisOJ Basic 熟悉的声音
查看>>
C# list导出Excel(二)
查看>>
CAS 单点登录模块学习
查看>>
Android应用开发-网络编程①
查看>>
input中的name,value以及label中的for
查看>>
静态库制作-混编(工程是oc为基础)
查看>>
jQuery 显示加载更多
查看>>
Confluence 6 系统运行信息中的 JVM 内存使用情况
查看>>
Confluence 6 升级以后
查看>>
用JS实现版面拖拽效果
查看>>
二丶CSS
查看>>
《avascript 高级程序设计(第三版)》 ---第二章 在HTML中使用Javascript
查看>>
JS一些概念知识及参考链接
查看>>
TCP/IP协议原理与应用笔记24:网际协议(IP)之 IP协议的简介
查看>>
SAP HANA开发中常见问题- 基于SAP HANA平台的多团队产品研发
查看>>
游戏中的心理学(一):认知失调有前提条件
查看>>
WHAT I READ FOR DEEP-LEARNING
查看>>
【Ruby】Ruby在Windows上的安装
查看>>
Objective C 总结(十一):KVC
查看>>