P4055 [JSOI2009]游戏 (二分图匹配+博弈思想)

P4055 [JSOI2009]游戏

分析:

每一次的移动可以看做两点之间连边,且不能重复经过一个点,如果走到一个点没有可以走的边了,则说明输了。

将棋盘黑白染色后连边即可得到一张二分图。

考虑先手应该放在哪个点会使得他自己赢。

先手放在非匹配点一定会赢。

因为对手只能走非匹配边,而先手在对手走了非匹配边之后走一条匹配边显然是最优的(非匹配边不一定有,而匹配边一定会有)

最后对手必输。

那么如果没有非匹配点怎么办?

先手必输。

因为此时是完美匹配,先手无论放在哪里,对手都会走一条匹配边把先手逼入绝路。

但这道题还要求输出第一次放的位置。

如何求非匹配点:

1. match==0

2. 删去这个点后仍能找到一条增广路(即这个点是可要可不要的)

#include<bits/stdc++.h>
using namespace std;
#define N 10005
#define nn 105
#define ri register int
int id[nn][nn],x[N],y[N],col[nn][nn],match[N],an[N],n,m,vis[N],fl[N];
int dx[]={0,0,1,-1},dy[]={1,-1,0,0};
char s[nn][nn];
vector<int> tot[2];
vector<int> e[N];
void init()
{
    int cnt=0;
    col[0][1]=1;
    for(ri i=1;i<=n;++i){
        int op=col[i-1][1]^1;
        for(ri j=1;j<=m;++j)
        id[i][j]=++cnt,x[id[i][j]]=i,y[id[i][j]]=j,col[i][j]=op,op^=1;
    }
}
int fll=0;
bool dfs(int u)
{    
    if(vis[u]) return false;
    vis[u]=1; 
    for(ri i=0;i<e[u].size();++i){
        int v=e[u][i];
        if(fl[v]) continue;
        if(!match[v] || dfs(match[v])){
            match[v]=u; match[u]=v;
            return true;
        }
    }
    return false;
}
void add(int a,int b) { e[a].push_back(b); e[b].push_back(a); }
int main()
{
    scanf("%d%d",&n,&m);
    init();
    for(ri i=1;i<=n;++i) scanf("%s",s[i]+1);
    for(ri i=1;i<=n;++i){
        for(ri j=1;j<=m;++j)
        if(s[i][j]=='.'){
            tot[col[i][j]].push_back(id[i][j]);
            if(col[i][j]) continue;
            for(ri k=0;k<=3;++k){
                int xx=i+dx[k],yy=j+dy[k];
                if(xx<1||yy<1||xx>n||yy>m || s[xx][yy]=='#') continue;
                add(id[i][j],id[xx][yy]);
            }
        }
    }
    int ans=0,cnt=0;
    for(ri i=0;i<tot[0].size();++i) memset(vis,0,sizeof(vis)),ans+=dfs(tot[0][i]);
    if(ans==max(tot[0].size(),tot[1].size())) printf("LOSE\n");
    else{
        printf("WIN\n");
        for(ri i=1;i<=n;++i)
         for(ri j=1;j<=m;++j)
          if(s[i][j]=='.'){
            int u=id[i][j]; 
            if(!match[u]) an[++cnt]=u;
            else{
                fl[u]=1;
                memset(vis,0,sizeof(vis));
                int tmp=dfs(match[u]);
                if(tmp) an[++cnt]=u,match[u]=0;
                fl[u]=0;
            }
        }
    }
    for(ri i=1;i<=cnt;++i) printf("%d %d\n",x[an[i]],y[an[i]]);
    return 0;
}
/*
3 3
.##
...
#.#

3 3
.#.
..#
#.#
*/
View Code

猜你喜欢

转载自www.cnblogs.com/mowanying/p/11794143.html