题解 | #模拟战役#
模拟战役
https://ac.nowcoder.com/acm/problem/14698
题意:
司机的大炮是前四行,小齐的大炮是后四行,小齐先开炮,然后司机开炮,小齐可以打司机任意一个大炮,但司机只能打小齐打自己的大炮的大炮,问小齐把司机的大炮打完最多能剩几个大炮。
思路:
-
因为一个大炮被打完后会产生一个 3 * 3 的波及范围,所以可以用一个dfs来搜索这个大炮的周围是否还有大炮,有大炮就继续搜下去,否则就停止,每次如果搜到了大炮,要把 '*' 改成 '.' , 因为已经把这个大炮记录下来了,并且往周围8个方向去搜索了,就相当于这个位置没大炮了。
-
小齐的最优策略:用连通块块内大炮数量少的去打司机就好了,注意小齐是先手,所以当司机的连通块和小齐的连通块一样多时,小齐还是赢的。
代码:
#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;
}