zoukankan      html  css  js  c++  java
  • 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
    ");
        else{
            printf("WIN
    ");
            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
    ",x[an[i]],y[an[i]]);
        return 0;
    }
    /*
    3 3
    .##
    ...
    #.#
    
    3 3
    .#.
    ..#
    #.#
    */
    View Code
  • 相关阅读:
    TreeView中找鼠标指向的节点
    自己写的一个分页控件源代码
    [JWF]只显示当前用户的WorkItem方法
    [JWF]安装Workflow Server后的中文界面补丁
    [JWF]JWF中调用WebService方法
    [JWF]配置Adobe Form Server Application
    [导入](HOWTO)将一个Xml中的节点复制到别一个Xml的节点上
    [JWF]Form Common button 执行生命周期
    [JWF]Special Buttons 执行生命周期
    [JWF]Participant Interface访问ActiveDirectory
  • 原文地址:https://www.cnblogs.com/mowanying/p/11794143.html
Copyright © 2011-2022 走看看