bzoj 1443: [JSOI2009]游戏Game (二分图博弈+网络流)
来源:互联网 发布:钢铁雄心4卡顿优化补丁 编辑:程序博客网 时间:2024/05/20 20:03
题目描述
传送门
题目大意:给出一个n*m的棋盘,有一些障碍点,先手选择一个点,然后后手可以移动到上下左右四个格子(不能是障碍点)。两人轮流移动,不能移动到已经到达过的位置,最后不能操作的人输。
题解
二分图博弈
特点:(1)博弈双方轮流进行操作
(2)博弈状态可以分成两类,分别对于匹配的X,Y集。任意合法决策使博弈状态改变
(3)任意状态不能重复到达
(4)不能操作的人输
对于这道来说,从一个点只能转移到他周围的四个点,那么我们对棋盘进行黑白染色,那么从黑点只能到达白点,从白点只能到达黑点。黑白点就可以看成不同的博弈状态。
那么如果把相邻的点用边连接,就构成了一个二分图。
对于先手必胜的点:一定是求完最大匹配后非匹配的点。
为什么?如果放到非匹配的点上,那么后手只能到达匹配点上(否则两个点能匹配,就不满足最大匹配了)
后手到达匹配点,那么先手就能走匹配边。
然后后手只能走一条不是匹配边的边,但是他到达的点一定有一条匹配边,那么先手就可以继续走。
所以最后不能操作的一定是后手。
但是对于一个二分图,可能的最大匹配不止一种,但是任意一个最大匹配中的的非匹配点都是合法的答案。
那么如何高效的统计呢?
1.从S出发,走容量不为0的边所能到达的属于X集合的点。能到达点可以分成两类:一是非匹配点(直接到达),二是经过一个非匹配点,然后走一条类似增广路所到达的匹配点(即可以将这条路上的匹配边和非匹配边翻转得到另一组解,而这条路的终点就是另一组解中的非匹配点)
2.从T出发,沿反向弧为0的边走所能到达的属于Y集合的点。能到达的点也可以分成两类,与上面S的分析方法类似。
那么二分图博弈就转换成了最大匹配问题。
代码
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#define N 103#define M 1000003#define inf 1000000000using namespace std;int point[M],nxt[M],v[M],remain[M],n,m,c[N][N],last[M],cur[M],vis[M],opt[M],px[M],py[M];int dx[10]={0,1,0,-1},dy[10]={1,0,-1,0},tot,cnt,top,st[M],deep[M],num[M],S,T;char ch[N][N];struct data{ int x,y;}a[M];void add(int x,int y,int z){ tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z; tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;}int addflow(int s,int t){ int now=t; int ans=inf; while (now!=s) { ans=min(ans,remain[last[now]]); now=v[last[now]^1]; } now=t; while (now!=s) { remain[last[now]]-=ans; remain[last[now]^1]+=ans; now=v[last[now]^1]; } return ans;}void bfs(int s,int t){ for (int i=1;i<=t;i++) deep[i]=t+1; queue<int> p; p.push(t); deep[t]=0; while (!p.empty()) { int now=p.front(); p.pop(); for (int i=point[now];i!=-1;i=nxt[i]) if (deep[v[i]]==t+1&&remain[i^1]) deep[v[i]]=deep[now]+1,p.push(v[i]); }}int isap(int s,int t){ bfs(s,t); int now=s; int ans=0; for (int i=1;i<=t;i++) num[deep[i]]++; for (int i=1;i<=t;i++) cur[i]=point[i]; while (deep[s]<t) { if (now==t) { ans+=addflow(s,t); now=s; } bool mark=false; for (int i=point[now];i!=-1;i=nxt[i]) if (deep[v[i]]+1==deep[now]&&remain[i]){ mark=true; cur[now]=i; last[v[i]]=i; now=v[i]; break; } if (!mark){ int minn=t+1; for (int i=point[now];i!=-1;i=nxt[i]) if (remain[i]) minn=min(minn,deep[v[i]]); if (!--num[deep[now]]) break; num[deep[now]=minn+1]++; if (now!=s) now=v[last[now]^1]; } } return ans;}void solve(int x,int t){ vis[x]=1; if (opt[x]==t) st[++top]=x; for (int i=point[x];i!=-1;i=nxt[i]) if (!vis[v[i]]&&(remain[i]==(t!=2))) solve(v[i],t);}int cmp(data a,data b){ return a.x<b.x||a.x==b.x&&a.y<b.y;}int main(){ freopen("a.in","r",stdin); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%s",ch[i]+1); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (ch[i][j]=='.') { c[i][j]=++cnt; px[cnt]=i; py[cnt]=j; } S=cnt+1; T=S+1; tot=-1; memset(point,-1,sizeof(point)); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (ch[i][j]=='.') { if ((i^j)&1) { add(S,c[i][j],1); opt[c[i][j]]=1; for (int k=0;k<4;k++) { int tx=i+dx[k]; int ty=j+dy[k]; if (tx<1||ty<1||tx>n||ty>m||ch[tx][ty]=='#') continue; add(c[i][j],c[tx][ty],1); } }else add(c[i][j],T,1),opt[c[i][j]]=2; } int flow=isap(S,T); if ((flow<<1)==cnt) { printf("LOSE\n"); return 0; } printf("WIN\n"); solve(S,1); memset(vis,0,sizeof(vis)); solve(T,2); for (int i=1;i<=top;i++) a[i].x=px[st[i]],a[i].y=py[st[i]]; sort(a+1,a+top+1,cmp); for (int i=1;i<=top;i++) printf("%d %d\n",a[i].x,a[i].y);}
- bzoj 1443: [JSOI2009]游戏Game (二分图博弈+网络流)
- BZOJ 1443 JSOI2009 游戏Game 二分图博弈
- bzoj 1443: [JSOI2009]游戏Game 二分图博弈
- [BZOJ]1443 [JSOI2009]游戏Game 二分图+博弈
- [二分图博弈] BZOJ 1443 [JSOI2009]游戏Game & BZOJ 2437 [Noi2011]兔兔与蛋蛋
- 【BZOJ1443】【JSOI2009】游戏Game 二分图+博弈
- 【bzoj1443】【JSOI2009】【游戏game】【二分图博弈】
- 【BZOJ1443】游戏Game(JSOI2009)-二分图最大匹配+博弈
- BZOJ 1443: [JSOI2009]游戏Game
- BZOJ 1443 JSOI 2009 游戏Game 二分图+博弈
- BZOJ 1443 [JSOI2009]游戏Game | UVALive 5882 Racing Car Trail
- 【BZOJ1443】游戏Game,博弈+二分图匹配
- [JSOI2009]游戏Game 匹配
- [BZOJ1443][JSOI2009]游戏Game
- BZOJ1443: [JSOI2009]游戏Game
- bzoj 2756: [SCOI2012]奇怪的游戏(网络流+二分)
- [BZOJ 1443]游戏Game
- acd - 1403 - Graph Game(博弈 + 二分图最大匹配)
- Android:自动弹出/隐藏 输入法软键盘
- 【敏捷开发每日一贴】敏捷教练和团队引导
- HDU 1728
- 【游戏设计】任务系统进化论
- 算法---折半查找
- bzoj 1443: [JSOI2009]游戏Game (二分图博弈+网络流)
- 去掉CodeIgniter(CI)默认url中的index.php
- GDOI2017总结
- Div+CSS布局相关属性(2)
- Linux环境下Qt Creator中SVN的使用方法
- Django开发的数据库连接问题。
- linux 编译安装TRMPdump(libRTMP)
- 拉格朗日插值法
- 定义矩形类