[LGOJ]P4055 [JSOI2009]游戏

本题标签:博弈&二分图

建议在做本题之前先看一看

[LGOJ]P3386 【模板】二分图最大匹配

[LGOJ]P4136 谁能赢呢?

如果是大佬当我没说 好的进入正题

题目大意:

小AA和小YY玩游戏,在这个游戏中,同一个格子不能进入两次,且不能将棋子移动到某些格子中去。当玩家无法继续移动棋子时,游戏结束,最后一个移动棋子的玩家赢得了游戏。

我们发现这题和[LGOJ]P4136 谁能赢呢是非常相似的,不过添加了障碍物并且不固定起点,这么一个小小的变化让一个橙题->紫题。

在P4136中,只需判断奇偶即可,但是,换种思路,因为一个人移了石头(棋子),另一人只能移相邻的,那么就成为了一个 1 ∗ 2 1*2 12的方块覆盖问题,于是便联想到这一题:ACWING372. 棋盘覆盖,不难想到,用二分图匹配求解

说回这一题,既然用二分图匹配,这里我们考虑一种经典的做法:黑白染色因为每一次走都是从黑到白或者从白到黑,所以需要建立二分图,我们对于每一个点,除去障碍,它能走到的点都连一条边

接下来我们来看这个二分图是否为完全匹配

RT–这是一种完全匹配方案,即每一个点都落在一条边上

橙色的为一种二分图匹配方案,当然连接的边肯定不止这一些,不过我们只描绘出一种二分图最大匹配方案即可,此时我们发现只要先手不论取哪一个点,后手都一定可以接着先手的那一步取二分图中对应的点,那么就很显然了,后手必胜。


接下来,我们考虑不完全匹配方案

说明非必须点即为不是所有最大匹配都需要的点,删掉它最大匹配数不变

看图:

这个图与上一个完全匹配的图相比多了一个节点7,这个7点就是一个非必须点此时不难想到,先手只需取到这个非必须节点,则问题就变为了上面的一个完全匹配的问题,只不过后手变成了先手。

可能有人会问,这个时候如果后手走到了另外一个非必须点呢? 答案是:不可能,因为如果又走向了一个非必须点,则此时必然构成一个新的匹配

但是这里面有一个漏洞:

在这里我省略了所有的其他边,只剩两种最大匹配方案(橙&蓝),此时若先手考虑二分图最大匹配方案蓝,则他会取取4这一非必须点,此时后手便可考虑最大匹配方案橙,跟着取3点,形成橙色匹配方案,此时经过模拟,我们发现后手赢了!那么我们需要做什么呢–找到所有最大匹配都非必须的点

这个时候,我们的任务变成了找到所有最大匹配都非必须的点,不难想到可以每次找一个非必须点并删除再继续跑二分图最大匹配,这样子显然是不可取的,那么我们应该怎么做呢?----我们发现找一个非必须点开始跑,若还能跑回这一边,则跑到的那个点也是非必须点,所以寻找步骤总结如下:

  1. 首先跑一下最大匹配,标记这些点
  2. 没有标记的点一定是非必须点,设为点集 S S S
  3. S S S中的点出发跑dfs,只是跟 i i i落在同一侧的点也是非必须点,因为这意味着从 i i i能到对面某个点 j j j,而j能返回 i i i的同侧点 k k k,说明用 i − > j i->j i>j可以替换掉原来的最大匹配中的边,所以 k k k也不是必须点
好的,具体就是这么多,总结:
  1. 如果是完全匹配,那么先手必输
  2. 如果不是完全匹配,那么先手挑一个非最大匹配的点落子,那么后手就会率先进入最大匹配的点,之后,先手就只用按照最打匹配的关系取选择落子,直到最大匹配走完,后手必输
  3. 需要找到所有最大匹配都非必须的点

讲解就到这里啦,接下来:

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
const int maxm=1005;
int n,m,tot,num;
int f[maxm][maxm],head[maxn],match[maxn],vis[maxn],color[maxn],unec[maxn];
char chess[maxm][maxm];
//num表示可放的点的个数,unec表示不必须的点
struct node
{
	int from,to,next;
}edge[maxn];
inline int add(int x,int y)
{
	edge[++tot].next=head[x];
	edge[tot].from=x;
	edge[tot].to=y;
	head[x]=tot;
}
inline int read()
{
	int s=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9')
	{
		if (c=='-')
		{
			f=-1;
		}
		c=getchar();
	}
	while (c>='0'&&c<='9')
	{
		s=s*10+c-48;
		c=getchar();
	}
	return s*f;
}
inline bool dfs(int x)                      //二分图的最大匹配
{
	for (int i=head[x];i;i=edge[i].next)
	{
		int y=edge[i].to;
		if (vis[y]==false)
		{
			vis[y]=true;
			if (match[y]==-1||dfs(match[y])==true)
			{
				match[y]=x;
				return true;
			}
		}
	}
}
inline void find(int x)                     //寻找不必须的点
{
	if (unec[x])
	{
		return ;
	}
	unec[x]=1;
	for (int i=head[x];i;i=edge[i].next)
	{
		int y=edge[i].to;
		if (match[y]!=-1)
		{
			find(match[y]);
		}
	}
}
int main()
{
	n=read(),m=read();
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=m;j++)
		{
			cin>>chess[i][j];
		}
	}
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=m;j++)
		{
			if (chess[i][j]=='.')
			{
				f[i][j]=++num;
				if ((i+j)%2==0)
				{
					color[f[i][j]]=1;       //染色
				}
			}
		}
	}
	for (int i=1;i<=n;i++)                  //建图
	{
		for (int j=1;j<=m;j++)
		{
			if (chess[i][j]=='.')
			{
				int x1=i,y1=j+1,x2=i+1,y2=j;
				if (f[x1][y1])
				{
					add(f[i][j],f[x1][y1]);
					add(f[x1][y1],f[i][j]);
				}
				if (f[x2][y2])
				{
					add(f[i][j],f[x2][y2]);
					add(f[x2][y2],f[i][j]);
				}
			}
		}
	}
	memset(match,-1,sizeof(match));
	int ans=0;
	for (int i=1;i<=num;i++)                //匈牙利
	{
		if (color[i])
		{
			memset(vis,0,sizeof(vis));
			ans+=dfs(i);
		}
	}
	tot+=ans;
	if (tot*2==num)                         //完全匹配
	{
		cout<<"LOSE"<<endl;
		return 0;
	}
	cout<<"WIN"<<endl;
	for (int i=1;i<=num;i++)
	{
		if (match[i]!=-1)
		{
			match[match[i]]=i;
		}
	}
	for (int i=1;i<=num;i++)
	{
		if (match[i]==-1)
		{
			find(i);
		}
	}
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=m;j++)
		{
			if (unec[f[i][j]])
			{
				cout<<i<<" "<<j<<endl;
			}
		}
	}
	return 0;
}
/*
3 3
.##
...
#.#
*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值