BZOJ 1443 [JSOI2009]游戏Game ——博弈论

好题。

首先看到棋盘,先黑白染色。

然后就是二分图的经典模型。

考虑最特殊的情况,完美匹配,那么先手必胜,

因为无论如何,先手走匹配边,后手无论走哪条边,总有对应的匹配边。

如果在不在最大匹配中出发,先手无论如何会走到最大匹配中,然后后手顺着匹配走,一定能胜利。

(万一又走到非最大匹配中呢,显然这样我们会找到一条增广路,与最大匹配不符)。

但是最大匹配不止又一种,所以我们需要判断是否在最大匹配中,需要寻找交错路。

如果在最大匹配中出发,显然先手必胜,(如果走到非最大匹配的点上,那么就相当于找到一条交错路可以替换,反而让非最大匹配换到了最大匹配中)

然后就相当于求一定不在最大匹配中的点了。

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
 
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
 
int mov[4][2]={{0,1},{1,0},{-1,0},{0,-1}};
vector <int> v[10005];
int id[105][105],a[105][105],n,m,cnt,vis[10005],linker[10005];
char s[105];
int ans[10005][2],tot=0,g[10005][10];
 
int dfs(int x)
{
    for (int i=1;i<=g[x][0];++i)
    {
        int t=g[x][i];
        if (vis[t]) continue;
        vis[t]=1;
        if (!linker[t]||dfs(linker[t]))
        {
            linker[t]=x;
            linker[x]=t;
            return 1;
        }
    }
    return 0;
}
 
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    F(i,1,n) F(j,1,m) id[i][j]=++cnt;
    F(i,1,n)
    {
        scanf("%s",s+1);
        F(j,1,m)
            if (s[j]=='#') a[i][j]=1;
    }
    F(i,1,n) F(j,1,m)
    if (!a[i][j]&&((i+j)%2)){
        int tx,ty;
        F(k,0,3)
        {
            tx=i+mov[k][0];ty=j+mov[k][1];
            if (tx>=1&&tx<=n&&ty>=1&&ty<=m&&!a[tx][ty])
            {
                g[id[i][j]][++g[id[i][j]][0]]=id[tx][ty];
                g[id[tx][ty]][++g[id[tx][ty]][0]]=id[i][j];
            }
        }
    }
    int cnt=0;
    F(i,1,n) F(j,1,m) if (!a[i][j]&&(i+j)%2)
    {
        memset(vis,0,sizeof vis);
        if (dfs(id[i][j])) cnt++;
    }
    F(i,1,n) F(j,1,m) if (!a[i][j])
    {
        memset(vis,0,sizeof vis);
        vis[id[i][j]]=1;
        if (!linker[id[i][j]]||dfs(linker[id[i][j]]))
        {
            tot++;
            ans[tot][0]=i;ans[tot][1]=j;
            linker[id[i][j]]=0;
        }
    }
    if (!tot) printf("LOSE\n");
    else
    {
        printf("WIN\n");
        F(i,1,tot) printf("%d %d\n",ans[i][0],ans[i][1]);
    }
}

  

posted @ 2017-03-13 23:34  SfailSth  阅读(218)  评论(0编辑  收藏  举报