题解:CF42B Game of chess unfinished

liuli688

2024-01-08 17:31:28

题解

其实这道题如果代码写好了还是很简单的。

思路:

如果白方能赢,则黑王此时所在和周围 8 个方向均处在白子攻击范围内,则输出 CHECKMATE

所以,只要模拟标出白车和白王的攻击范围即可。代码如下。

#define STR string
#define BK break
#define CTN continue
#define FP(i,a,b) for(i = a;i < b;i++)
#define FM(i,a,b) for(i = a;i > b;i--)
#define FL(i,a,b) for(i = a;i <= b;i++)
#define FG(i,a,b) for(i = a;i >= b;i--)
STR r1,r2,wk,bk;
int xx,yy,i,j;

bool c[8][8],atk[8][8];//c 是标记是否有棋子,atk 是攻击范围
void markr(int x,int y)//标记车
{
    FG(i,x,0)
    {
        if(i == x)//注意棋子本身不在攻击范围内
            CTN;
        else
            atk[i][y] = true;
        if(c[i][y])//如果碰到棋子,跳出,赋值后判定保证棋子本身会被覆盖到
            BK; 
    }
    FP(i,x,8)
    {
        if(i == x)
            CTN;
        else
            atk[i][y] = true;
        if(c[i][y])
            BK;
    }
    FG(i,y,0)
    {
        if(i == y)
            CTN;
        else
            atk[x][i] = true;
        if(c[x][i])
            BK;
    }
    FP(i,y,8)
    {
        if(i == y)
            CTN;
        else
            atk[x][i] = true;
        if(c[x][i])
            BK;
    }
}
void markk(int x,int y)//标记白王
{
    FL(i,-1,1)
        FL(j,-1,1)
        {
            xx = x + i;
            yy = y + j;
            if(xx >= 0 && xx < 8 && yy >= 0 && yy < 8)//防止 RE
                atk[xx][yy] = true;
        }
    atk[x][y] = false;//棋子同样不在攻击范围内
}

但是,棋子的攻击范围可能会被其它棋子阻挡。上文的代码由于棋子本身不在攻击范围内,所以黑王可以通过吃掉白子来生存。由于碰到棋子后的跳出在赋值后,判定保证棋子本身会被覆盖到。所以棋子如果处在另一个棋子的攻击范围内黑王不能吃。

然后,就是开始的输入、标记和判定。

void check(int x,int y)
{
    FL(i,-1,1)
        FL(j,-1,1)
        {
            xx = x + i;
            yy = y + j;
            if(xx >= 0 && xx < 8 && yy >= 0 && yy < 8)//注意此处 9 个格子均需判定
                if(!atk[xx][yy])
                {
                    OUT("OTHER");
                    return ;
                }
        }
    OUT("CHECKMATE");//如果全在攻击范围内,输出 CHECKMATE
} 
MAIN
{
    SPEEDUP;
    IN(r1 >> r2 >> wk >> bk);
    c[r1[0]-'a'][r1[1]-'1'] = true;//标记棋子
    c[r2[0]-'a'][r2[1]-'1'] = true;
    c[wk[0]-'a'][wk[1]-'1'] = true;
    c[bk[0]-'a'][bk[1]-'1'] = true;
    markr(r1[0]-'a',r1[1]-'1');//车
    markr(r2[0]-'a',r2[1]-'1');
    markk(wk[0]-'a',wk[1]-'1');//白王
    check(bk[0]-'a',bk[1]-'1');//判定
    END;
}

这段代码看起来很完美,于是提交。CF 上结果如下。

7
Time: 0 ms, memory: 4 KB
Verdict: WRONG_ANSWER
Input
a1 a2 c4 c2
Participant's output
OTHER
Jury's answer
CHECKMATE
Checker comment
wrong answer 1st words differ - expected: 'CHECKMATE', found: 'OTHER'

WA 了。手动模拟一下攻击范围(R 表示车,W 表示白王,B 表示黑王,x 表示攻击范围)

 12345678
aRR------
bxxxxx...
cxBxKx...
dx.xxx...
ex.......
fx.......
gx.......
hx.......

我们发现,d2 这个位置没有被覆盖,事实上王即使走到了 d2 也会暴露在 a2 的车下面。于是我们作如下改动:

MAIN
{
    SPEEDUP;
    IN(r1 >> r2 >> wk >> bk);
    c[r1[0]-'a'][r1[1]-'1'] = true;//标记棋子
    c[r2[0]-'a'][r2[1]-'1'] = true;
    c[wk[0]-'a'][wk[1]-'1'] = true;
    //c[bk[0]-'a'][bk[1]-'1'] = true;注释掉,代表黑王即使移动也会暴露在攻击范围下
    markr(r1[0]-'a',r1[1]-'1');//车
    markr(r2[0]-'a',r2[1]-'1');
    markk(wk[0]-'a',wk[1]-'1');//白王
    check(bk[0]-'a',bk[1]-'1');//判定
    END;
}

于是就 AC 啦!

代码:

#define MAIN signed main()
#define SPEEDUP ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define USING using namespace std
#define END return 0
#define LL long long
#define ULL unsigned long long
#define LD long double
#define STR string
#define EL '\n'
#define BK break
#define CTN continue
#define INF INT_MAX
#define UINF INT_MIN
#define IN(n) cin >> n
#define OUT(n) cout << n
#define OUTL(n) cout << n << EL
#define FP(i,a,b) for(i = a;i < b;i++)
#define FM(i,a,b) for(i = a;i > b;i--)
#define FL(i,a,b) for(i = a;i <= b;i++)
#define FG(i,a,b) for(i = a;i >= b;i--)

#include <bits/stdc++.h>
USING;
STR r1,r2,wk,bk;
int xx,yy,i,j;

bool c[8][8],atk[8][8];
void markr(int x,int y)
{
    FG(i,x,0)
    {
        if(i == x)
            CTN;
        else
            atk[i][y] = true;
        if(c[i][y])
            BK; 
    }
    FP(i,x,8)
    {
        if(i == x)
            CTN;
        else
            atk[i][y] = true;
        if(c[i][y])
            BK;
    }
    FG(i,y,0)
    {
        if(i == y)
            CTN;
        else
            atk[x][i] = true;
        if(c[x][i])
            BK;
    }
    FP(i,y,8)
    {
        if(i == y)
            CTN;
        else
            atk[x][i] = true;
        if(c[x][i])
            BK;
    }
}
void markk(int x,int y)
{
    FL(i,-1,1)
        FL(j,-1,1)
        {
            xx = x + i;
            yy = y + j;
            if(xx >= 0 && xx < 8 && yy >= 0 && yy < 8)
                atk[xx][yy] = true;
        }
    atk[x][y] = false;
}
void check(int x,int y)
{
    FL(i,-1,1)
        FL(j,-1,1)
        {
            xx = x + i;
            yy = y + j;
            if(xx >= 0 && xx < 8 && yy >= 0 && yy < 8)
                if(!atk[xx][yy])
                {
                    OUT("OTHER");
                    return ;
                }
        }
    OUT("CHECKMATE");
} 
MAIN
{
    SPEEDUP;
    IN(r1 >> r2 >> wk >> bk);
    c[r1[0]-'a'][r1[1]-'1'] = true;
    c[r2[0]-'a'][r2[1]-'1'] = true;
    c[wk[0]-'a'][wk[1]-'1'] = true;
    markr(r1[0]-'a',r1[1]-'1');
    markr(r2[0]-'a',r2[1]-'1');
    markk(wk[0]-'a',wk[1]-'1');
    check(bk[0]-'a',bk[1]-'1');
    END;
}