题意:

司机的大炮是前四行,小齐的大炮是后四行,小齐先开炮,然后司机开炮,小齐可以打司机任意一个大炮,但司机只能打小齐打自己的大炮的大炮,问小齐把司机的大炮打完最多能剩几个大炮。

思路:

  1. 因为一个大炮被打完后会产生一个 3 * 3 的波及范围,所以可以用一个dfs来搜索这个大炮的周围是否还有大炮,有大炮就继续搜下去,否则就停止,每次如果搜到了大炮,要把 '*' 改成 '.' , 因为已经把这个大炮记录下来了,并且往周围8个方向去搜索了,就相当于这个位置没大炮了。

  2. 小齐的最优策略:用连通块块内大炮数量少的去打司机就好了,注意小齐是先手,所以当司机的连通块和小齐的连通块一样多时,小齐还是赢的。

代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int N=10,M=110;
char maze[N][M];
int m;
int dir[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
int cnt1,cnt2;//记录两人连通块数量
int num;
int a[N*M],b[N*M];//记录两人连通块内大炮数量
void dfs(int x,int y,int c)
{
    maze[x][y]='.';
    num++;
    
    for(int i=0;i<8;i++)
    {
        int dx=x+dir[i][0],dy=y+dir[i][1];
        if(dx<0 || dx>=c || dy<0 || dy>=m) continue;//c是为了看是小齐的领地,还是司机的领地
        if(maze[dx][dy]=='.') continue;
        dfs(dx,dy,c);
    }
    
}

int main(){
    cin>>m;
    for(int i=0;i<8;i++)
    {
        for(int j=0;j<m;j++)
        {
            cin>>maze[i][j];
        }
    }
    
    for(int i=0;i<4;i++)//司机的联通块数量
    {
        for(int j=0;j<m;j++)
        {
            if(maze[i][j]=='*')
            {
                num=0;
                dfs(i,j,4);
                a[cnt1++]=num;//每个连通块内有几个大炮
            }
        }
    }
    
    for(int i=4;i<8;i++)//小齐的连通块数量
    {
        for(int j=0;j<m;j++)
        {
            if(maze[i][j]=='*')
            {
                num=0;
                dfs(i,j,8);
                b[cnt2++]=num;//每个连通块内有几个大炮
            }
            
        }
    }
    
    if(cnt1>cnt2) puts("-1");
    else
    {
        sort(b,b+cnt2);//拿连通块内大炮数量小的先打
        int sum=0;
        for(int i=cnt1-1;i<cnt2;i++) sum+=b[i];//因为小齐是先手,所以从cnt-1开始
        cout<<sum<<endl;
    }
    
    return 0;
}