传送门
思路:
很巧妙的思路
将二分图的匹配与博弈相联系
给出定理:
若二分图中去掉起点后仍存在最大匹配(与先前的最大匹配数相等),那么先手必输;反之先手必胜
关于证明,我昨天晚上和今天中午想了很久,随便口胡一下
先考虑起点一定在最大匹配中(即定理中所说的’先手必胜’情况)的情况:
那么只要先手只要移到起点的匹配点就可以了
因为显然走的边是匹配边->非匹配边->匹配边->非匹配边…
如果表示一对匹配点为
(xi,yi)
的话(设起点为
x1
)
那么走的点就是
x1−>y1−>x2−>y2...
也就是说只要对手(在y点)找到了一个(x点)
那么我们(在x点)一定可以走当前点的匹配点
最终肯定是对手输
会不会对手(在y点)不走到x点?也就是说对手走了一条非匹配边到达了非匹配点
显然是不能的
因为这样的话把之前路径上的匹配边变成非匹配边,非匹配边变成匹配边,这又是一个最大匹配,同时起点也不再是匹配点,这与给出的条件’起点一定在最大匹配中’矛盾,所以不成立
再考虑’先手必输’的情况
在这种情况下,我们可以把起点看做一个非匹配点
只能从起点出发走到一个已匹配点中,这个已匹配点一定在删除起点的二分图中的最大匹配里(至于证明的话,因为如果该点不在最大匹配中,那么起点和该点在原图中构成一个新的匹配,而原图匹配数应该等于现图匹配数,所以’该点不在最大匹配’不成立)
然后就转化成上面先手必胜的情况了
证毕
然后就可以暴力枚举一下了……
好像会T,不管了,压了压常数,跑了6000ms+……
注意每次跑匈牙利之前要清空vis数组,而且每次删除完点后还要再加进去,也就是再跑一遍匈牙利就可以了
代码:
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,tot,cnt;
bool vis[10003],del[10003];
int a[103][103],id[103][103],first[10003],belong[10003],ax[10003],ay[10003];
int dx[]={0,0,1,-1},dy[]={1,-1,0,0};
struct edge{
int v,next;
}e[40005];
int in()
{
char c=getchar();
while (c!='.'&&c!='#') c=getchar();
if (c=='.') return 1;
return 0;
}
void add(int u,int v){e[++tot]=(edge){v,first[u]};first[u]=tot;}
bool find(int x)
{
if (del[x]) return 0;
for(int i=first[x];i;i=e[i].next)
if (!del[e[i].v]&&!vis[e[i].v])
{
vis[e[i].v]=1;
if (!belong[e[i].v]||find(belong[e[i].v]))
{
belong[e[i].v]=x;
belong[x]=e[i].v;
return 1;
}
}
return 0;
}
main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
{
a[i][j]=in();
if (a[i][j])
id[i][j]=++cnt;
}
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
if (id[i][j])
for (int k=0;k<4;++k)
if (id[i+dx[k]][j+dy[k]])
add(id[i][j],id[i+dx[k]][j+dy[k]]);
for (int i=1;i<=cnt;++i)
if (!belong[i])
memset(vis,0,sizeof(vis)),
find(i);
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
if (id[i][j])
{
int tmp=belong[id[i][j]];
belong[id[i][j]]=belong[tmp]=0;
del[id[i][j]]=1;
memset(vis,0,sizeof(vis));
if (!tmp||find(tmp))
{
ax[++ax[0]]=i,ay[ax[0]]=j;
memset(vis,0,sizeof(vis));
find(id[i][j]);
}
else belong[tmp]=id[i][j],belong[id[i][j]]=tmp;
del[id[i][j]]=0;
}
if (ax[0]) puts("WIN");
else puts("LOSE");
for (int i=1;i<=ax[0];++i) printf("%d %d\n",ax[i],ay[i]);
}