top1编程
← 返回题目
题解

黑白棋子移动

1 条题解

  • 0
    @ 2026-7-28 22:31:39
    #include <bits/stdc++.h>
    using namespace std;
    char s[105][105];
    int dx[9] = {0, -1, -1, -1, 0, 0, 1, 1, 1};
    int dy[9] = {0, -1, 0, 1, -1, 1, -1, 0, 1};
    int T,n,cnt,mx,cnt0,cnt1;
    
    // 函数:计算在(x,y)放置颜色c的棋子后,能翻转多少个对方的棋子
    // 参数x,y: 落子坐标(1-indexed)
    // 参数c:   落子的颜色('x'或'o')
    // 返回值:  能翻转的对方棋子总数
    int f(int x,int y,char c)
    {
        int fz=0;  // 累计翻转的棋子数
        // 遍历8个方向(从1到8,跳过第0个)
        for(int i=1;i<=8;i++)
        {
            int tx=x+dx[i];  // 沿着当前方向走一步
            int ty=y+dy[i];
            int df=0;  // 记录连续遇到的对方棋子个数
            // 在棋盘范围内一直走(棋盘范围 1~n)
            while(tx>=1&&tx<=n&&ty>=1&&ty<=n)
            {
                if(s[tx][ty]=='.')  // 遇到空格,不能翻转
                    break;
                if(s[tx][ty]==c)    // 遇到同色棋子,中间夹着的df个对方棋子可以翻转
                {
                    fz+=df;      // 累加翻转数
                    break;
                }
                // 遇到对方棋子,继续往前走
                tx+=dx[i];
                ty+=dy[i];
                df++;             // 对方棋子数+1
            }
        }
        return fz;
    }
    
    int main()
    {
        cin>>T;  // 读入测试数据组数
        while(T--)
        {
            cin>>n;  // 读入棋盘大小
            // 读入棋盘(1-indexed,第1行第1列开始存储)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    cin>>s[i][j];
            
            // cnt: 统计棋盘上已经有多少个棋子(非空格)
            cnt=0;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(s[i][j]!='.')
                        cnt++;
            
            cnt0=0;
            cnt1=0;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(s[i][j]=='x')
                        cnt0++;//黑棋(x)数量
                    else if(s[i][j]=='o')
                        cnt1++;//cnt1: 白棋(o)数量
            
            // mx: 在最优位置落子能翻转的最大对方棋子数
            mx=0;
            // 遍历所有空格(1-indexed),寻找最优落子位置
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(s[i][j]=='.')
                    {
                        // 根据当前已下棋子数的奇偶性判断当前该谁下
                        // cnt%2==0: 已下偶数个棋子 → 黑方先手,所以该黑方(x)下
                        // cnt%2==1: 已下奇数个棋子 → 该白方(o)下
                        if(cnt%2==0)
                            mx=max(mx,f(i,j,'x'));  // 黑方落子,计算能翻转多少白棋
                        else
                            mx=max(mx,f(i,j,'o'));  // 白方落子,计算能翻转多少黑棋
                    }
            
            // 输出答案:落子后本方棋子数与对方棋子数的最大差值
            // 公式推导:
            //   落子前差值 = 本方 - 对方
            //   落子后:本方+1(新落子)+ mx(翻转过来的),对方 - mx(被翻转的)
            //   新差值 = (本方+1+mx) - (对方-mx) = (本方-对方) + 1 + 2*mx
            if(cnt%2==0)
                // 当前该黑棋(x)下,本方是黑棋
                cout<<cnt0-cnt1+2*mx+1<<endl;
            else
                // 当前该白棋(o)下,本方是白棋
                cout<<cnt1-cnt0+2*mx+1<<endl;
        }
        return 0;
    }
    
    • 1