loj6033.「雅礼集训 2017 Day2」棋盘游戏

题意

见到棋盘首先想黑白染色,之后对这个二分图跑一个最大匹配。

假如一个棋子放在了一个非匹配点上,那么先手必败,因为后手每次都有匹配边可以走。

于是我们要求有多少个点可能不在一个最大匹配中:
考虑一个非匹配点\(x\),假如它连向了一个匹配点\(y\),那么它就能替换掉当前当前和这个匹配点匹配的点\(z\),而这时\(z\)也可以进行同样的操作。

于是我们从每个非匹配\(x\)出发进行\(dfs\),途经的和\(x\)同一集合的点都满足要求。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=150;
int n,m,cnt_edge,tim,ans;
int head[maxn*maxn],match[maxn*maxn],vis[maxn*maxn];
char a[maxn][maxn];
bool check[maxn*maxn];
inline int read()
{
    char c=getchar();int res=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    return res*f;
}
struct edge{int to,nxt;}e[maxn*maxn*8]; 
inline void add_edge(int u,int v)
{
    e[++cnt_edge].nxt=head[u];
    head[u]=cnt_edge;
    e[cnt_edge].to=v;
}
inline int id(int i,int j){return (i-1)*m+j;}
bool dfs(int x)
{
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(vis[y]==tim)continue;
        vis[y]=tim;
        if(!match[y]||dfs(match[y])){match[y]=x;match[x]=y;return 1;}
    }
    return 0;
}
void dfs_ans(int x)
{
    check[x]=1;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(!check[match[y]])dfs_ans(match[y]);
    }
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(a[i][j]=='#')continue;
            if(i<n&&a[i+1][j]=='.')add_edge(id(i,j),id(i+1,j)),add_edge(id(i+1,j),id(i,j));
            if(j<m&&a[i][j+1]=='.')add_edge(id(i,j),id(i,j+1)),add_edge(id(i,j+1),id(i,j));
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(((i+j)&1)&&a[i][j]=='.')
                tim++,dfs(id(i,j));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(a[i][j]=='.'&&!match[id(i,j)]&&!check[id(i,j)])
                dfs_ans(id(i,j));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(check[id(i,j)])ans++;
    printf("%d\n",ans);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(check[id(i,j)])printf("%d %d\n",i,j);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/nofind/p/12149757.html