做训练赛遇到的一道题,感觉很好。
大致题意:
现在给你一个地图n*m,' . '代表是空格子,' * '代表是有柱子阻隔。现在你站在a点,要走到b点。走的时候要遵循一个规则:必须走相邻的格子,如果相邻的格子为有柱子格子,那么这个格子与有柱子的格子相邻的边起火,如果一个有柱子的格子的两条或者多条不同的边起火了,那么这个格子就会变成空格子。现在问你,你是否能从a点走到b点。
n<=500,m<=500.
大致思路:
首先想到是bfs,但是这个起火的状态怎么表示呢?而且我们注意到一个空格子是可以反复走的。
我的思路是定义一个三维数组v[x][y][i],代表想x,y所在的格子是否往i反向走过。(i四种状态,上下左右)如果x,y向i方向走之后所在的格子是柱子格子,那么就让这个柱子格子的check值加1(我们可以再开个数组check,代表柱子格子的边有几条着火,当check[x][y]的值为2时,就把它变成’ . ')。如果不是,那么就正常走。
每次走之后我们都把v当前的[x][y][i]记录为1,代表这个格子已经走过旁边的某个格子了,以后不用再走了。这样就避免了重复入队。
代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
char rc[550][550];
int vis[550][550][4];
int check[550][550];
int r,c;
int dis[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
typedef struct node
{
int x;
int y;
} node;
map<int,int>M;
int bfs(node a,node b)
{
queue<node>Q;
Q.push(a);
int flag=1;
while(!Q.empty())
{
//printf("***\n");
node aa=Q.front();
if(aa.x==b.x&&aa.y==b.y&&rc[aa.x][aa.y]!='*')return 1;
Q.pop();
for(int i=0; i<4; i++)
{
int xx=aa.x+dis[i][0];
int yy=aa.y+dis[i][1];
if(xx>=1&&xx<=r&&yy>=1&&yy<=c)
{
if(rc[xx][yy]=='.'&&!vis[aa.x][aa.y][i])
{
vis[aa.x][aa.y][i]=1;
node k;
k.x=xx;
k.y=yy;
Q.push(k);
}
else
{
if(!vis[aa.x][aa.y][i])
{
vis[aa.x][aa.y][i]=1;
check[xx][yy]++;
if(check[xx][yy]==2)
{
rc[xx][yy]='.';
node k;
k.x=xx;
k.y=yy;
Q.push(k);
}
}
}
}
}
}
return 0;
}
int main()
{
int t;
while(~scanf("%d",&t))
{
while(t--)
{
scanf("%d%d",&r,&c);
memset(vis,0,sizeof(vis));
memset(check,0,sizeof(check));
for(int i=1; i<=r; i++)
{
for(int j=1; j<=c; j++)
{
cin>>rc[i][j];
}
}
node st,ed;
cin>>st.x>>st.y>>ed.x>>ed.y;
if(bfs(st,ed))
{
printf("YES\n");
}
else
printf("NO\n");
}
}
}