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

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

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

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

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

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

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

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

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

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

最新文章

  1. Html.DropDownLis绑定数据库
  2. 帮助理解委托、匿名委托、Lambda表达式还有事件
  3. C#关闭word进程
  4. C# 正则表达式 验证:数字、带小数点数字、电话和手机
  5. C#语言的几个层次
  6. LVM管理
  7. java模拟get/post提交
  8. 【干货】平安打卡神器E行销刷脸考勤破解,是怎么做到的?
  9. 再看ExpressionTree,Emit,反射创建对象性能对比
  10. 彻底搞懂Scrapy的中间件(三)
  11. @vue/cli 3 打包文件读取绝对路径处理
  12. C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 树形选择项目的标准例子
  13. 从头到尾使用Geth的说明-1-安装
  14. python中json.load()、json.loads()、json.dump()、json.dumps()的区别
  15. 转:servlet的url-pattern匹配规则详细描述
  16. CSRF(跨站请求伪造)攻击
  17. Spring 多数据源事务配置问题
  18. Office WORD如何设置表格背景颜色
  19. Docker入门篇(三)之docker-compose单机编排
  20. 【Go】基础语法之接口

热门文章

  1. js 实现List
  2. std::shared_ptr 和普通指针的转换
  3. BZOJ3307雨天的尾巴——线段树合并
  4. BZOJ3505 CQOI2014数三角形(组合数学)
  5. Uva101-STL模拟
  6. Catenyms POJ - 2337(单词+字典序输出路径)
  7. 自学Python1.5-Centos内python2识别中文
  8. 【BZOJ4820】[SDOI2017]硬币游戏(高斯消元)
  9. WorkFlow基础实战
  10. &#39;RegAsm.exe&#39; 不是内部或外部命令