HDU 4775 Infinite Go 解题报告

题目

题意:

在一个有上、左边界,无右、下边界的棋盘上下棋,如果一片同颜色的棋子周围(只考虑横纵的四个格子)都是边界或者敌方的棋子,则它们会被消去。A、B两人轮流下棋,如果一方下了一个棋子使得有棋子要被消去时,先消敌方的,消完敌方后再看是否要消去己方。已知下棋的位置,求最后剩的棋子个数。

题解:

用map存下每个棋子的位置,就可以预处理棋子之间的邻接关系。然后依次下棋,遇到同色的棋子则用并查集合并,并记录该集合周围空格的个数。

为方便空格的个数如此定义:

#*

##

如果#是白棋,*表示没有棋子,那么空格个数是2。

如果一片棋子周围没有空格了,则消去。


代码:


//Time:78ms
//Memory:1104KB
//Length:3344B
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
#define MAXN 10010
#define MP(x,y) make_pair(x,y)
#define FI first
#define SE second
map<pair<int,int>,int>ma;
const int dis[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
struct _no
{
    int x,y,c;
    int to[4];
    _no(int _x,int _y)
    {
        x=_x,y=_y;
        c=-1;
        for(int i=0;i<4;++i)    to[i]=-1;
    }
    _no(){}
}no[MAXN];
int top,fa[MAXN],col[MAXN],xy[MAXN];
int que[MAXN];
bool vi[MAXN];
int findfa(int n)
{
    if(fa[n]!=n)
        fa[n]=findfa(fa[n]);
    return fa[n];
}
inline void smu(int a,int b)
{
    a=findfa(a),b=findfa(b);
    if(a==b)    return ;
    fa[b]=a;
    col[a]+=col[b];
}
void del(int h)
{
    int he=0,ta=0;
    que[ta++]=h;
    while(he<ta)
    {
        h=que[he++];
        for(int i=0;i<4;++i)
        {
            int p=no[h].to[i];
            if(p!=-1)
            {
                if(no[p].c==no[h].c&&!vi[p])
                    que[ta++]=p,vi[p]=1;
                else    if(no[p].c==!no[h].c)
                    ++col[findfa(p)];
            }
        }
        no[h].c=-1;
    }
}
int main()
{
    //freopen("/home/moor/Code/input","r",stdin);
    int ncase,n;
    scanf("%d",&ncase);
    while (ncase--)
    {
        memset(vi,0,sizeof(vi));
        top=0;
        ma.clear();
        scanf("%d",&n);
        for(int i=0;i<n;++i)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if(ma.find(MP(x,y))==ma.end())
            {
                ma[MP(x,y)]=top;
                xy[i]=top;
                no[top++]=_no(x,y);
            }
            else    xy[i]=ma[MP(x,y)];
        }
        for(int i=0;i<top;++i)
            for(int j=0;j<4;++j)
            {
                int tx=no[i].x+dis[j][0],ty=no[i].y+dis[j][1];
                map<pair<int,int>,int> ::iterator ite=ma.find(MP(tx,ty));
                if(ite!=ma.end())
                    no[i].to[j]=ite->SE;
            }
        for(int i=0;i<n;++i)    fa[i]=i,col[i]=0;
        for(int i=0;i<n;++i)
        {
            int p=xy[i];
            int c=no[p].c=i&1;
            vi[p]=0;
            for(int j=0;j<4;++j)
            {
                int tx=no[p].x+dis[j][0],ty=no[p].y+dis[j][1];
                if(tx>0&&ty>0&&(no[p].to[j]==-1||no[no[p].to[j]].c==-1))
                    ++col[p];
            }
            for(int j=0;j<4;++j)
            {
                int tmp=no[p].to[j];
                if(tmp!=-1&&no[tmp].c!=-1)
                {
                    --col[findfa(tmp)];
                    if(no[tmp].c==c)
                        smu(tmp,p);
                }
            }
            for(int j=0;j<4;++j)
            {
                int tmp=no[p].to[j];
                if(tmp!=-1&&no[tmp].c==!c&&col[findfa(tmp)]==0)
                    del(tmp);
            }
            for(int j=0;j<4;++j)
            {
                int tmp=no[p].to[j];
                if(tmp!=-1&&no[tmp].c==c&&col[findfa(tmp)]==0)
                    del(tmp);
            }
            if(no[p].c!=-1&&col[findfa(p)]==0)   del(p);
        }
        int nb=0,nw=0;
        for(int i=0;i<top;++i)
            if(no[i].c==0)
                ++nb;
            else    if(no[i].c==1)
                ++nw;
        printf("%d %d\n",nb,nw);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值