2019.01.06-dtoj-2437: [Noi2011]兔兔与蛋蛋

题目描述:


算法标签:二分图匹配

思路:

首先,看作是操作看成是空格移动,我叫空格的位置是起点。

如果对整个棋盘进行黑白染色,即所以与起点所在格子同色的黑色棋子和与起点所在格子不同色的白色格子才可以走到。于是对于棋盘中的有效点进行黑白匹配,每次移动会使走的那个点变成无效点。于是每次在二分图匹配中删去一个点再继续匹配。

以下代码:

#include<bits/stdc++.h>
#define il inline
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=45,M=1605,dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
bool del[M],f[N][N],win[2005];char s[N][N];
int n,m,id[N][N],tot,si,sj,nt,d[M],mat[M],head[M],ne[M<<1],to[M<<1],cnt;
il int read(){int x;char ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;}
il void insert(int x,int y){ne[++cnt]=head[x];head[x]=cnt;to[cnt]=y;}
il bool dfs(int x){
    d[x]=nt;
    for(int i=head[x];i;i=ne[i]){
        if(del[to[i]]||d[to[i]]==nt)continue;
        d[to[i]]=nt;
        if(!mat[to[i]]||dfs(mat[to[i]])){
            mat[to[i]]=x;mat[x]=to[i];
            return 1;
        }
    }
    return 0;
}
int main()
{
    n=read();m=read();for(int i=1;i<=n;i++)scanf(" %s",s[i]+1);
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
        if(s[i][j]=='.'){si=i;sj=j;s[i][j]='X';break;}
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
        if(s[i][j]=='O'&&((abs(si-i)+abs(sj-j))&1))id[i][j]=++tot;
        if(s[i][j]=='X'&&((abs(si-i)+abs(sj-j))&1)==0)id[i][j]=++tot;
    }
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
        if(id[i][j])for(int k=0;k<4;k++){
            int xx=i+dx[k],yy=j+dy[k];
            if(id[xx][yy])insert(id[i][j],id[xx][yy]);
        }
    for(int i=1;i<=tot;i++)if(!mat[i])++nt,dfs(i);
    int q=read();q<<=1;
    for(int i=1;i<=q;i++){
        int x=id[si][sj];
        if(mat[x]){int v=mat[x];mat[x]=mat[v]=0;del[x]=1;nt++;win[i]=!dfs(v);}
        else del[x]=1;
        si=read(),sj=read();
    }
    int ans=0;for(int i=1;i<=q;i+=2)ans+=(win[i]&&win[i+1]);
    printf("%d\n",ans);
    for(int i=1;i<=q;i+=2)if(win[i]&&win[i+1])printf("%d\n",(i+1)>>1);
    return 0;
}
View Code

 

 

转载于:https://www.cnblogs.com/Jessie-/p/10230686.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值