bzoj2437: [Noi2011]兔兔与蛋蛋

本文探讨了在一个黑白染色的棋盘上进行的游戏,通过分析O和X的移动规律,将其转化为二分图上的博弈问题。每一步移动等同于删除一个节点,并通过寻找增广路来判断游戏的胜负状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先把棋盘黑白染色,那么对于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;
}

 

转载于:https://www.cnblogs.com/AKCqhzdy/p/9615319.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值