博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ】1443: [JSOI2009]游戏Game
阅读量:6956 次
发布时间:2019-06-27

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

【算法】博弈论+二分图匹配(最大流)

【题解】方格图黑白染色得到二分图,

二分图博弈:当起点不属于某个最大匹配时,后手必胜。

问题转化为那些点不属于某个最大匹配。

先找到一个最大匹配,非匹配点加入答案。

假设一个匹配点要解放成为非匹配点,则与其匹配的点必须去匹配另一个点。如果另一个点也是匹配点,则其对面又要去找另一个点。

最终得到结论,一个匹配点的解放,必须有一个非匹配点进入最大匹配。

那么从S一侧的非匹配点出发,沿着“非匹配边-匹配边”的路径走,途中经过的S一侧的匹配点都可以被解放出来。

从T一侧的非匹配点出发也做一次,得到答案。

#include
#include
#include
#include
using namespace std;const int maxn=10010,inf=0x3f3f3f3f;const int dx[]={
0,-1,1,0,0};const int dy[]={
0,0,0,1,-1};struct edge{
int v,from,flow;}e[maxn*10];int first[maxn],id[110][110],idx[maxn],idy[maxn],S,T,cnt,tot=1,d[maxn],ans[maxn],ansnum,cur[maxn],col[maxn],n,m;char s[110];bool map[110][110],vis[maxn];void insert(int u,int v,int w){tot++;e[tot].v=v;e[tot].flow=w;e[tot].from=first[u];first[u]=tot; tot++;e[tot].v=u;e[tot].flow=0;e[tot].from=first[v];first[v]=tot;}queue
q;bool bfs(){ memset(d,-1,sizeof(d)); q.push(S);d[S]=0; while(!q.empty()) { int x=q.front();q.pop(); for(int i=first[x];i;i=e[i].from) if(d[e[i].v]==-1&&e[i].flow) { d[e[i].v]=d[x]+1; q.push(e[i].v); } } return d[T]!=-1;}int dinic(int x,int a){ if(x==T||a==0)return a; int flow=0,f; for(int& i=cur[x];i;i=e[i].from) if(d[e[i].v]==d[x]+1&&(f=dinic(e[i].v,min(a,e[i].flow)))) { e[i].flow-=f; e[i^1].flow+=f; a-=f; flow+=f; if(a==0)break; } return flow;}void dfs(int x,int f){ vis[x]=1; if(col[x]==f&&x!=S&&x!=T)ans[++ansnum]=x; for(int i=first[x];i;i=e[i].from) if(e[i].flow==f&&!vis[e[i].v])dfs(e[i].v,f);}int main(){ scanf("%d%d",&n,&m); cnt=0; for(int i=1;i<=n;i++) { scanf("%s",s+1); for(int j=1;j<=m;j++)if(s[j]=='.') { id[i][j]=++cnt; idx[cnt]=i;idy[cnt]=j; map[i][j]=1; } } S=0;T=++cnt; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++)if(map[i][j]) { if((i+j)&1) { insert(S,id[i][j],1); for(int k=1;k<=4;k++)if(map[i+dx[k]][j+dy[k]]) { insert(id[i][j],id[i+dx[k]][j+dy[k]],1); } col[id[i][j]]=1; } else{insert(id[i][j],T,1);col[id[i][j]]=0;} } } while(bfs()) { for(int i=0;i<=cnt;i++)cur[i]=first[i]; dinic(S,inf); } ansnum=0; memset(vis,0,sizeof(vis)); dfs(S,1); memset(vis,0,sizeof(vis)); dfs(T,0); if(ansnum) { printf("WIN\n"); sort(ans+1,ans+ansnum+1); for(int i=1;i<=ansnum;i++)printf("%d %d\n",idx[ans[i]],idy[ans[i]]); } else printf("LOSE\n"); return 0;}
View Code

 

转载于:https://www.cnblogs.com/onioncyc/p/7236773.html

你可能感兴趣的文章
Stanford NLP学习笔记:7. 情感分析(Sentiment)
查看>>
程序员最应该真正读的书籍
查看>>
ubuntu下安装程序的三种方法
查看>>
js之全选即点击全选标签可选择全部复选框
查看>>
自我介绍
查看>>
垂直外边距叠加问题
查看>>
Shell简介:什么是Shell,Shell命令的两种执行方式
查看>>
Linux .bashrc文件设置快速访问快捷键
查看>>
spring多个context:property-placeholder不生效问题
查看>>
入职培训笔记记录--day9(1、指针函数与函数指针、函数指针数组 2、malloc memset 3、递归函数 4、结构体 5、共用体---》大小端 6、枚举)...
查看>>
SQL查询
查看>>
四个程序员的一天
查看>>
排序三:插入排序
查看>>
JDBC也就那么回事
查看>>
类的加载顺序 (一、编译时常量与运行时常量)
查看>>
servlet:启动的时机
查看>>
笔记:2016-06-23
查看>>
5.22心得
查看>>
你赚的钱大部分来自你的圈子,而非你的知识
查看>>
字符串递归
查看>>