2018.10.25-dtoj-3989-五子棋(fir)

题目描述:

就像题目名字一样,他们在玩一种类似于五子棋的游戏,只是规则和五子棋有一些不同。 就像五子棋一样,ITer和Kitty依次在棋盘上放置棋子,ITer放置黑子,Kitty放置白子。与五子棋不同的是,当一种颜色的X个棋子组成一行或一列或一个对角线的时候(X不一定等于5),执该颜色的子的玩家胜利。

如图,当X=5时,ITer胜利的三种方法:

下了一会儿后,ITer和Kitty觉得无聊了。于是,他们又加了一个类似围棋的规则:当一个连通分量(四连通)的棋子的四周被另一种棋子围住时,这些棋子就消失了,我们称这些子被“吃掉”了。

如图,三颗白棋的四周都被黑棋围住,所以这三颗棋子就应该消失。成为下图:

现在ITer和Kitty下了N步棋,ITer先手,每次下棋的位置用坐标表示。 现在ITer想知道,下了N步棋后,是否有人赢了,在第几步赢了,是否有不合法的走法。

输入:

输入文件第一行两个正整数N,X,表示下了N步棋,当一种颜色的X个棋子组成一行或一列或一个对角线的时候,执该颜色的子的玩家胜利。 接下来的N行,每行2个正整数Xi,Yi,当i为奇数时,表示ITer在第 i步下在了(Xi,Yi)上,当i为偶数时,表示Kitty在第 i步下在了(Xi,Yi)上。

输出:

如果ITer在前N步赢了,则输出“ITer X”(中间用空格连接),X表示ITer在第几步赢了。 如果Kitty在前N步赢了,则输出“Kitty X”(中间用空格连接),X表示Kitty在第几步赢了。 如果在N步以内有不合法的步,则输出“illegal”。

一步不合法有以下几种情况:
1. 这步下在了已经有棋子的格子上。
2. 在没有吃掉对方棋子的情况下,该步子所在的联通分量的棋子被对方的棋子吃掉。如图1,白子走在了红叉的位置上是不合法的,因为这样会使该联通分量被吃掉。

如图2,如果白子走在红叉的位置上是合法的,因为它吃掉了右边的两个黑子。走完这步后白子不会消失,棋盘上的子变成图3。

请忽视某一个人赢了以后出现的不合法的步。 如果既没有出现不合法的步,又没有决出胜负,则输出“draw”。 假设棋盘是无限的。

数据范围:

Subtask 1 30%:N≤20,X≤5,Xi,Yi≤10。 Subtask 2 70%:N≤1000,X≤10,1≤Xi,Yi≤1000 。

算法标签:模拟!!

恨模拟的根源是这道题!铭记了

思路:

只要你能想到的暴力都不会T,但我还是调了很久,最后绝望了....气啊....对于连成一条的暴力往两边扩张,看能不能达到个数。每次从当前点向外搜索,先判自己能否成为边界包死别人。再搜一次判断自己会不会被包死。

以下为调了半下午仍旧只有70+的我的代码(仅作纪念):

#include<bits/stdc++.h>
#define il inline
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=1005;int n,st,a[N][N],op,fa[N],mx,my;bool pd,vis[N][N];
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;}
il int getfa(int x){if(!fa[x])return x;return fa[x]=getfa(fa[x]);}
il bool work(int x,int y,int col){
    if(a[x][y]==3-col)return 1;if(a[x][y]==0)return 0;
    vis[x][y]=1;
    for(int i=0;i<4;i++){
        int xx=dx[i]+x,yy=dy[i]+y;
        if(xx<0||yy<0||xx>mx||yy>my)return 0;
        if(!vis[xx][yy]&&work(xx,yy,col)==0)return 0;
    }
    return 1;
}
il void change(int x,int y){
    if(!vis[x][y])return;vis[x][y]=0;a[x][y]=0;
    for(int i=0;i<4;i++){
        int xx=dx[i]+x,yy=dy[i]+y;
        change(xx,yy);
    }
}
il void c(int x,int y){
    if(!vis[x][y])return;vis[x][y]=0;
    for(int i=0;i<4;i++){
        int xx=dx[i]+x,yy=dy[i]+y;c(xx,yy);
    }
}
int main()
{
    freopen("123.out","w",stdout);
    n=read();st=read();op=1;
    for(int i=1;i<=n;i++){
        int x=read(),y=read();if(pd)continue;mx=max(mx,x);my=max(my,y);
        if(op==1&&a[x][y]!=0){puts("illegal");pd=1;continue;}
        if(op==2&&a[x][y]!=0){puts("illegal");pd=1;continue;    }
        a[x][y]=op;
        int k=x,res=1;while(k-1>0&&a[k-1][y]==op)res++,k--;
        k=x;while(k+1<=n&&a[k+1][y]==op)res++,k++;
        if(res>=st){
            if(op==1)printf("ITer %d
",i);
            if(op==2)printf("Kitty %d
",i);
            pd=1;continue;
        }
        res=1;k=y;while(k-1>0&&a[x][k-1]==op)res++,k--;
        k=y;while(k+1<=n&&a[x][k+1]==op)res++,k++;
        if(res>=st){
            if(op==1)printf("ITer %d
",i);
            if(op==2)printf("Kitty %d
",i);
            pd=1;continue;
        }
        int k1=x,k2=y;res=1;
        while(k1+1<=n&&k2+1<=n&&a[k1+1][k2+1]==op)res++,k1++,k2++;
        k1=x,k2=y;while(k1-1>0&&k2-1>0&&a[k1-1][k2-1]==op)res++,k1--,k2--;
        if(res>=st){
            if(op==1)printf("ITer %d
",i);
            if(op==2)printf("Kitty %d
",i);
            pd=1;continue;
        }
        for(int i=0;i<4;i++)if(x+dx[i]<=mx&&x+dx[i]>0&&y+dy[i]<=my&&y+dy[i]>0){
            int res=work(x+dx[i],y+dy[i],3-op);if(res==1)change(x+dx[i],y+dy[i]);
            else c(x+dx[i],y+dy[i]);
        }
        if(pdd(x,y))puts("illegal");
        op=3-op;
    }
    if(!pd)puts("draw");
  return 0;
}
View Code

以下为在sgx神犇“援助”下的代码(没耐心本人)

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define _(d) while(d(isdigit(ch=getchar())))
const int N=1004;int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
int a[N][N],cnt,n,k,C,id[N][N],mx,my;bool vis[N];
il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;}
il bool J(int r,int x,int y,int col,bool is,int fl){
    vis[id[x][y]]=1;
    bool ff=0;
    for(int i=0;i<4;i++){
        int tx=x+dx[i],ty=y+dy[i];
        if((!a[tx][ty])||(is&&a[tx][ty]==3-col&&(!vis[id[tx][ty]])
        &&(!J(r,tx,ty,3-col,0,0))))ff=1;
    }
    for(int i=0;i<4;i++){
        int tx=x+dx[i],ty=y+dy[i];
        if(a[tx][ty]==col){
            if((!vis[id[tx][ty]])&&J(r,tx,ty,col,is,ff|fl)) ff=1;
        }
    }
    if(ff)return true;
    if(!is&&!(fl|ff)) a[x][y]=0;
    return false;
} 
il bool work(int r,int x,int y,int t1,int t2){
    int x1=0,x2=0;
    for(int i=0;i<=k;i++){
        if(a[x+i*t1][y+i*t2]==C)x1++;else break;
    }
    for(int i=0;i<=k;i++){
        if(a[x-i*t1][y-i*t2]==C)x2++;else break;
    }
    if(x1+x2-1>=k){
        if(C==1)printf("ITer %d
",r);
        else printf("Kitty %d
",r);
        return 0;
    }
    return 1;
}
int main(){
    n=read();k=read();C=2;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)vis[j]=0;
        C=3-C; int x,y;x=read();y=read();id[x][y]=++cnt;
        if(a[x][y]){puts("illegal");return 0;}
        a[x][y]=C;
        memset(vis,0,sizeof(vis));
        if(!J(i,x,y,C,1,0)){puts("illegal");return 0;}
        mx=max(mx,x);my=max(my,y);
        for(int j=-1;j<=1;j++)for(int l=-1;l<=1;l++){
            if(!j&&!l)continue;
            if(!work(i,x,y,j,l)) return 0;
        }
    }
    puts("draw");
    return 0;
}
View Code

讨厌什么就要让它向你请安!立下爆刷模拟flag

原文地址:https://www.cnblogs.com/Jessie-/p/9851022.html