终于出现了一个我会写的题QAQ
题意
题意很简单,就是有n列,上面四列是a的,下面四列是b的,每个人都有几架炮,对轰嘛,就是你打我我打你,现在a开挂,有全图视野,b不知道,所以a先手,b被打了之后就会有a开炮的那架炮的视野(所以b就会果断反击),然后呢如果被打到了大炮,大炮就会炸,炸的话会把周围的炮也炸了,题意中波及的范围周围八个反向,然后问a能不能打过,如果能打过输出最多还剩多少炮,不能输出-1。输入描述
第1行输入一个整数m,表示地图的宽度。
第2-5行,每行输入一串长度为m的字符串,代表司机的大炮部署。(大炮为"*"号,空地为“.”号)
第6-9行,每行输入一串长度为m的字符串,代表齐齐的大炮部署。(大炮为"*"号,空地为“.”号)
数据保证:0<m≤100
输出描述
输出一行,一个整数。代表摧毁所有司机的大炮后最多保留几门大炮。如果不能摧毁所有司机的大炮,则输出-1。
解析
首先,既然我们开挂,那么我们肯定是拿自己如果被打的话连锁爆炸少的去打对面多的,因为我们开炮打了别人,别人肯定是优先打我们露出来的这个炮比较划算,这样子换的话最后如果我们打的过的话我们剩下的就是最多的,这样子我们就先把我们自己的和对面的炮,连锁在一起的画成一个区域,毕竟如果我们打对面的甲炮会引爆乙炮,打乙炮同样是会引爆甲炮,所以我采用了并查集,将会连锁引爆的炮划在一起,这样子如果我们的区域大于等于对面我们就能赢(因为我们先手,最后一轮把对面的打掉之后对面就没有炮反击了),关于并查集->这个是我以前学习并查集的时候写的博客。代码
#include<bits/stdc++.h> using namespace std; const int N=101; char a[N][N]; int dx[8]={0,0,1,-1,1,-1,1,-1}; int dy[8]={1,-1,0,0,1,-1,-1,1}; int fa[N*N],siz[N*N],m,sav[N*N],e,t; inline int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); } inline void merge(int x,int y){ int a=find(x),b=find(y); if(a!=b){ fa[a]=b,siz[b]+=siz[a]; } } int main(void){ scanf("%d",&m); for(int i=1;i<=8;++i){ for(int j=1;j<=m;++j){ scanf(" %c",&a[i][j]);fa[(i-1)*m+j]=(i-1)*m+j,siz[(i-1)*m+j]=1; } } for(int i=1;i<=8;++i){ for(int j=1;j<=m;++j){ if(a[i][j]=='*'){ for(int k=0;k<8;++k){ int x=i+dx[k],y=j+dy[k]; if(((i<=4&&x&&x<=4)||(i>4&&x>4&&x<=8))&&y&&y<=m){ if(a[x][y]=='*'){ merge((x-1)*m+y,(i-1)*m+j); } } } } } } for(int i=1;i<=8;++i){ for(int j=1;j<=m;++j){ if(a[i][j]=='*'&&fa[(i-1)*m+j]==(i-1)*m+j){ if(i<=4){ ++t; }else{ sav[++e]=siz[(i-1)*m+j]; } } } } if(e<t){ printf("-1\n"); return 0; } sort(sav+1,sav+e+1); int ans=0; for(int i=t;i<=e;++i){ ans+=sav[i]; } printf("%d\n",ans); return 0; }