码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 2437: [Noi2011]兔兔与蛋蛋

时间:2017-12-29 21:50:13      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:lin   ret   ==   alt   false   .com   head   stdin   div   

Description

技术分享图片

Solution

考虑犯错误的条件:之前是处于必胜状态,该操作之后就变成了必败状态.

我们可以把这个过程看成两人对网格图进行黑白染色,变成了一个二分图模型,即当前位置向相邻不同颜色的位置连边,构成的二分图,一次游戏相当于一个最大匹配.
技术分享图片

一个结论:如果一定存在包含当前位置的最大匹配,那么处于先手必胜状态
证明:
因为当前点不处于最大匹配中,那么只有非匹配边可以走,假设走到了\(v\)\(v\)点则可以走匹配边,假设走了一条匹配边,则到达的下一个点只能走非匹配边,因为匹配的点是\(v\), 综上:先手只能一直沿着匹配边走,而后手有匹配边可以走,所以不是必胜状态

所以只需要判断一个点是否在一定在最大匹配中了
方法是:删除该点,再跑一次最大匹配,如果能成功匹配则不满足条件.

一个细节:一定不会存在回路,即一个点只会走一次,所以走过的点不能再进入匹配中

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=45;
int x,y,nxt[N*N*8],to[N*N*8],num=0,w[N*N];
int n,m,a[N][N],id[N][N],cnt=0;char s[N];
bool vis[N*N],ans[N*N*2];int b[N*N],head[N*N];
void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
inline bool dfs(int x){
    for(int i=head[x];i;i=nxt[i]){
        int u=to[i];
        if(!vis[u] && !w[u]){
            vis[u]=1;
            if(!b[u] || dfs(b[u])){
                b[u]=x;b[x]=u;
                return true;
            }
        }
    }
    return false;
}
void build(){
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(((i+j)&1)^((x+y)&1)^(a[i][j]==1))
                id[i][j]=++cnt;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(!id[i][j])continue;
            if(i<n && id[i+1][j])link(id[i][j],id[i+1][j]);
            if(i>1 && id[i-1][j])link(id[i][j],id[i-1][j]);
            if(j<m && id[i][j+1])link(id[i][j],id[i][j+1]);
            if(j>1 && id[i][j-1])link(id[i][j],id[i][j-1]);
        }
}
void work()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        for(int j=1;j<=m;j++){
            if(s[j]=='X')a[i][j]=1;
            else if(s[j]=='O')a[i][j]=2;
            else x=i,y=j,a[i][j]=1;
        }
    }
    build();
    for(int i=1;i<=cnt;i++){
        if(!b[i]){
            memset(vis,0,sizeof(vis));
            dfs(i);
        }
    }
    int Q,ret=0;
    cin>>Q;
    for(int i=1;i<=Q<<1;i++){
        w[id[x][y]]=1;
        if(!b[id[x][y]])ans[i]=0;
        else{
            int u=id[x][y],v=b[u];
            b[u]=b[v]=0;
            memset(vis,0,sizeof(vis));
            ans[i]=(!dfs(v));
        }
        scanf("%d%d",&x,&y);
    }
    for(int i=1;i<=Q;i++)
        if(ans[2*i-1]&ans[i<<1])ret++;
    printf("%d\n",ret);
    for(int i=1;i<=Q;i++)
        if(ans[2*i-1]&ans[i<<1])printf("%d\n",i);
}

int main()
{
    freopen("pp.in","r",stdin);
    freopen("pp.out","w",stdout);
    work();
    return 0;
}

bzoj 2437: [Noi2011]兔兔与蛋蛋

标签:lin   ret   ==   alt   false   .com   head   stdin   div   

原文地址:https://www.cnblogs.com/Yuzao/p/8146313.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!