这种模拟题是很类似于南阳ccpc国赛的铜牌题难度的

所以,想要保证拿奖,这种恶心的题还是得写出来


题目大意是:现在有个棋盘,里面有黑色和白色的棋子,五子棋的游戏规则。问你,三步之内,是不是可能出现某一方的必胜情况

分析:

A:如何判断哪方棋子先落子?

如果黑色棋子数目=白色,那么黑先落子

如果黑色棋子数目=白色棋子数目+1,那么白色先落子

其他情况,不合法


B:如何判断第一步的情况?

第一步,先落子方想要赢:只需要在棋盘上找到某一个点,使得成至少五子相连即可


C:如何判断第二步的情况?

第二步,也就是说后落子方想要赢

条件1:先落子方赢不了

条件2:后落子方需要有两个能够获胜的点(因为是博弈,所以后落子方如果只有一个获胜点,那么先落子方会堵住那个点)


D:第三步的情况

条件1:先落子方第一步赢不了,我们在棋盘上任意一个空白格子落上一个先落子方的棋子

然后就和C差不多了


所以,就落实到了两个问题:

第一个:获胜点怎么找

第二个:怎么判断当前情况是不是能够防守的(最多一个获胜点可以防守,大于一个获胜点就已经无法防守了)


#include<bits/stdc++.h>
using namespace std;

const int maxn=15;
int mp[20][20];
const int dx[]={1,1,0,-1,-1,-1,0,1};
const int dy[]={0,-1,-1,-1,0,1,1,1};
int n;

char name[10][10]={"","white","black"};

bool init(){
    scanf("%d",&n);
    if (!n) return false;
    memset(mp,0,sizeof(mp));
    int x,y,c;
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&x,&y,&c);
        mp[x+1][y+1]=c+1;
    }
    return true;
}

bool inmap(int x,int y){
    return (x>=1&&x<=maxn&&y>=1&&y<=maxn);
}

bool countandcheck(int turn,int x,int y){
    int dir,nx,ny,cnt,k;
    for(dir=0;dir<4;dir++){
        cnt=0;
        for(k=1;;++k){
            nx=x+k*dx[dir];
            ny=y+k*dy[dir];
            if (inmap(nx,ny)&&mp[nx][ny]==turn) cnt++;
            else break;
        }
        for(k=1;;++k){
            nx=x+k*dx[dir+4];
            ny=y+k*dy[dir+4];
            if (inmap(nx,ny)&&mp[nx][ny]==turn) cnt++;
            else break;
        }
        if (cnt>=4) return true;
    }
    return false;
}

bool canwin(int turn,int &x,int &y){
    for(int i=1;i<=maxn;i++)
    for(int j=1;j<=maxn;j++){
        if (mp[i][j]) continue;
        if (countandcheck(turn,i,j)){
            x=i;y=j;return true;
        }
    }
    return false;
}

bool candefend(int turn,int &x,int &y){
    int cnt=0;
    for(int i=1;i<=maxn;i++)
    for(int j=1;j<=maxn;j++){
        if (mp[i][j]) continue;
        if (countandcheck(3-turn,i,j)){
            cnt++;
            if (cnt>1) return false;
            x=i;y=j;
        }
    }
    return true;
}

void work(){
    int cnt[3],turn,x,y;
    cnt[1]=cnt[2]=0;
    for(int i=1;i<=maxn;i++)
    for(int j=1;j<=maxn;j++)
        cnt[mp[i][j]]++;
    if (cnt[1]==cnt[2]) turn=2;
    else if (cnt[1]+1==cnt[2]) turn=1;
    else{
        puts("Invalid.");
        return;
    }
    if (canwin(turn,x,y)) printf("Place %s at (%d,%d) to win in 1 move.\n",name[turn],x-1,y-1);
    else{
        if (!candefend(turn,x,y)) printf("Lose in 2 moves.\n");
        else{
            for(int i=1;i<=maxn;i++)
            for(int j=1;j<=maxn;j++)
            if (mp[i][j]==0){
                mp[i][j]=turn;
                if (!canwin(3-turn,x,y)&&!candefend(3-turn,x,y)){
                    printf("Place %s at (%d,%d) to win in 3 moves.\n",name[turn],i-1,j-1);
                    return;
                }
                mp[i][j]=0;
            }
            printf("Cannot win in 3 moves.\n");
        }
    }
}

int main(){
    //freopen("input.txt","r",stdin);
    while(init())
        work();
    return 0;
}