题解 P4328 【[COCI2006-2007#1] Slikar】
这道题不难,乍一看数据很小:
基本流程:
我们并不需要每走一步就模拟扩散一次洪水,首先这样可能有点麻烦,其次时间复杂度较大。
显而易见,洪水的扩散是不会受刺猬走动影响的
用一个当然如果有人用DFS写出来也没必要惊讶)来进行模拟水到每个点的流动的最小时间(预处理)
然后跑一个
最后:
特判:
-
-
BFS$:跑完整个图没有到达的,肯定就是$KAKTUS
至于障碍嘛,其实有没有障碍都是一样的,只不过你跑不到那,水也不能流到那……
参考程序:(程序出处:crh1272336175的题解)
#include<bits/stdc++.h>
using namespace std;
const int M=55;
int n,m,sx,sy,ex,ey,ans=0x3f3f3f3f;
char str[M][M];
int t[M][M],visited[M][M];//t用于记录洪水到达某个点的时间
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};//上下左右
struct flood
{
int x,y,t;//坐标和洪水到达的时间
flood(const int &x,const int &y, const int &t):x(x),y(y),t(t){}
};
queue<flood> qriver,q;
void bfs_water()
{
while(!qriver.empty())
{
flood now=qriver.front(); qriver.pop();
for(int i=0; i<4; i++)
{
int nx=now.x+dx[i],ny=now.y+dy[i];
if(nx>=1 && nx<=n && ny>=1 && ny<=m)//判断边界
if(str[nx][ny]=='.' && !visited[nx][ny])//能走得通且没访问过'
{
visited[nx][ny]=1;
if(t[nx][ny]>now.t+1) t[nx][ny]=now.t+1;
qriver.push(flood{nx,ny,now.t+1});
}
}
}
}
void bfs_person()
{
memset(visited,0,sizeof visited);
q.push(flood{sx,sy,0});
while(!q.empty())
{
flood now=q.front(); q.pop();
for(int i=0; i<4; i++)
{
int nx=now.x+dx[i],ny=now.y+dy[i];
if(nx==ex && ny==ey)
ans=min(ans,now.t+1);
if(nx>=1 && nx<=n && ny>=1 && ny<=m)//判断边界
if(str[nx][ny]=='.' && t[nx][ny]>now.t+1&& !visited[nx][ny])//能走得通且没访问过
{
visited[nx][ny]=1;
if(t[nx][ny]>now.t+1) t[nx][ny]=now.t+1;
q.push(flood{nx,ny,now.t+1});
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
{
scanf("%s",str[i]+1);
for(int j=1; j<=m; j++)
{
char c=str[i][j];
if(c=='S') sx=i,sy=j;
else if(c=='D') ex=i,ey=j;
else if(c=='*') qriver.push(flood{i,j,0});
}
}
memset(t,0x3f3f3f3f,sizeof t);
bfs_water();
bfs_person();
if(ans==0x3f3f3f3f) puts("KAKTUS");
else printf("%d\n",ans);
return 0;
}