[luogu1971 NOI2011] 兔兔与蛋蛋游戏 (二分图博弈)

[luogu1971 NOI2011] 兔兔与蛋蛋游戏 (二分图博弈)

传送门

Solution

补一篇二分图博弈
这个博客写的很详细qwq: https://www.cnblogs.com/maijing/p/4703094.html

Code

//By Menteur_Hxy
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
#define E(i,u) for(register int i=head[u],v;i;i=nxt[i])
#define add(a,b) nxt[++cnt]=head[a],to[cnt]=b,head[a]=cnt
using namespace std;

const int N=50;
int mv[5]={0,1,0,-1,0};
int n,m,tot,top,tim,X,Y,cnt;
bool mp[N][N],jud[2010],ban[N*N];
int head[N*N],to[N*N*N*N],nxt[N*N*N*N],vis[N*N];
int id[N][N],mat[N*N],ans[1010];
char ch[N];

bool dfs(int u) {
    if(ban[u]) return false;
    E(i,u) if(vis[(v=to[i])]!=tim&&!ban[v]) {
        vis[v]=tim;
        if(!mat[v] || dfs(mat[v])) {
            mat[v]=u;mat[u]=v;
            return true;
        }
    }
    return false;
}

int main() {
    cin>>n>>m;
    F(i,1,n) {
        scanf("%s",ch+1);
        F(j,1,m) if(ch[j]=='O') mp[i][j]=0;
            else if(ch[j]=='X') mp[i][j]=1;
            else if(ch[j]=='.') mp[i][j]=1,X=i,Y=j;
    }
    F(i,1,n) F(j,1,m) id[i][j]=++tot;
    F(i,1,n) F(j,1,m) if(mp[i][j]) F(k,0,3) {
        int x=i+mv[k],y=j+mv[k+1];
        if(mp[x][y]||x<1||x>n||y<1||y>m) continue;
        add(id[i][j],id[x][y]); add(id[x][y],id[i][j]);
    }
    F(i,1,n) F(j,1,m) if(mp[i][j]) ++tim,dfs(id[i][j]);
    int q; cin>>q;
    F(i,1,q+q) {
        int now=id[X][Y],v=mat[now];
        ban[now]=true;//!!!
        if(v) {
            mat[now]=mat[v]=0; 
            ++tim; jud[i]=!dfs(v);
        }
        cin>>X>>Y;
    }
    F(i,1,q) if(jud[i+i-1]&jud[i+i]) ans[++top]=i;
    printf("%d\n",top);
    F(i,1,top) printf("%d\n",ans[i]);
    return 0;
}
posted @ 2018-09-08 11:28 Menteur_Hxy 阅读( ...) 评论( ...) 编辑 收藏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值