题解
黑白棋子移动
1 条题解
-
0
#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