bzoj2437: [Noi2011]兔兔与蛋蛋

先把棋盘黑白染色,那么对于O,当且仅当它所处的格子颜色和空格不一样才会移动,X相似,那么对于这些O/X,最多也就是被移动1次而已。同时每次空格每次移动所处颜色都是在改变

那么就是二分图博弈啊。而走一步相当于删除一个点,然后每次就让被删的那个点去找增广路,找到了就必败,反之必胜。

蛋蛋走完必胜,兔兔再走又是必胜就是下错了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const int dx[4]={0,-1,0,1};
const int dy[4]={-1,0,1,0};

struct node
{
    int x,y,next;
}a[11000];int len,last[11000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}

int match[11000];
int ti,v[11000]; bool bo[11000];
bool findmuniu(int x)
{
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(v[y]!=ti&&bo[y]==true)
        {
            v[y]=ti;
            if(match[y]==0||findmuniu(match[y])==true)
            {
                match[y]=x;
                match[x]=y;
                return true;
            }
        }
    }
    return false;
}

int n,m,prex,prey,nowx,nowy;
char ss[110][110]; int blen,b[11000],aslen,as[11000];
int point(int x,int y){return (x-1)*m+y;}
bool win(int x,int y)
{
    int p=point(x,y);
    bo[p]=false;
    if(match[p]==0)return false;
    
    match[match[p]]=0; ti++;
    bool bk=(!findmuniu(match[p]));
    match[p]=0;
    return bk;
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",ss[i]+1);
        for(int j=1;j<=m;j++)
            if(ss[i][j]=='.')prex=i,prey=j;
    }
    blen=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if((i+j)%2==(prex+prey)%2&&ss[i][j]!='O')
            {
                b[++blen]=point(i,j);
                for(int k=0;k<=3;k++)
                {
                    int ti=i+dx[k],tj=j+dy[k];
                    if(ti>0&&ti<=n&&tj>0&&tj<=m&&ss[ti][tj]=='O')
                        ins(point(i,j),point(ti,tj)), ins(point(ti,tj),point(i,j));
                }
            }
    
    ti=0;memset(v,0,sizeof(v));
    memset(bo,true,sizeof(bo));
    for(int i=1;i<=blen;i++)
    {
        ti++;
        findmuniu(b[i]);
    }
    
    int AK; aslen=0;
    scanf("%d",&AK);
    for(int i=1;i<=AK;i++)
    {
        scanf("%d%d",&nowx,&nowy);
        int w1=win(prex,prey);
        int w2=win(nowx,nowy);
        if(w1&&w2)as[++aslen]=i;
        scanf("%d%d",&prex,&prey);
    }
    printf("%d\n",aslen);
    for(int i=1;i<=aslen;i++)
        printf("%d\n",as[i]);
    
    return 0;
}

 

posted @ 2018-09-09 21:50  AKCqhzdy  阅读(205)  评论(0编辑  收藏  举报