放火烧草,每次可选两个点放
题解: n,m范围非常小,所以先用vector存起来草的位置,在一个个枚举即可。然后用一个计数器,来计算草的数量,当草数量为0时,就返回步数。
(T了很多发,因为没有加vis判断访问)
AC 代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
#define ll long long
#define up(i,a,n) for(int i=a;i<=n;i++)
#define down(i,a,n) for(int i=a;i>=n;i--)
#define pb push_back
const int maxn=15;
char Map[maxn][maxn];
bool vis[maxn][maxn];
bool vis1[maxn][maxn];
int _move[4][2]={0,1,0,-1,1,0,-1,0};
int n,m,granum,granum1;
struct node
{
int x,y,cnt,granum;
void ss(int x1,int y1,int cnt1){
x=x1,y=y1;cnt=cnt1;
}
};
bool check(int x,int y)
{
if(Map[x][y]=='.'||x<1||x>n||y<1||y>m||!vis[x][y])return false;
return true;
}
int bfs(node a,node b){
queue<node>q;
q.push(a);
q.push(b);//入队
while(!q.empty())//一波一波一步一步走
{
node ss=q.front();q.pop();
if(vis[ss.x][ss.y])granum--;
else continue;
vis[ss.x][ss.y]=false;
if(granum==0)return ss.cnt;
ss.cnt++;
up(i,0,3)
{
ss.x+=_move[i][0];
ss.y+=_move[i][1];
if(check(ss.x,ss.y))
{
q.push(ss);
}
ss.x-=_move[i][0];
ss.y-=_move[i][1];
}
}//走完后
return 999999;
}
int main()
{
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++)
{ vector<node>grass;//草地
granum1=0;//用来记录草地的块数
scanf("%d%d",&n,&m);
memset(Map,'\000',sizeof(Map));
memset(vis1,true,sizeof(vis1));
up(i,1,n)scanf("%s",Map[i]+1);//存图
up(i,1,n)
{
up(j,1,m)
{
if(Map[i][j]=='#')
{
node ss;
ss.ss(i,j,0);
grass.pb(ss);//草地进栈
granum1++;//草地块数+1
}
else vis1[i][j]=false;//如果为‘.’,则不能走
}
}
if(granum1<=2){
printf("Case %d: 0\n",cas);
continue;
} //如果草地的块数小于等于2,直接输出0
int ans=999999;
up(i,0,grass.size()-1)//枚举每个起点,进入bfs。
{
for(int j=i;j<grass.size();j++)
{
memcpy(vis,vis1,sizeof(vis1));
granum=granum1;
ans=min(bfs(grass[i],grass[j]),ans);
}
}
if(ans!=999999)printf("Case %d: %d\n",cas,ans);
else printf("Case %d: -1\n",cas);
}
}