题面
Description
Input
Output
Sample Input & Sample Output
【样例输入1】
4 5
##...
..1#@
432#.
...#.
【样例输出1】
4
【样例输入2】
4 4
#78#
.612
.543
..@.
【样例输出2】
6
【样例输入3】
3 2
3@
2#
1#
【样例输出3】
-1
HINT
题解
\(dfs\)玄学复杂度过去了……
注:这题用\(bfs\)的时间复杂度更低,为\(O(nm4^k)\)。我只是考场上用了\(dfs\)加小小的优化卡过去了。这篇题解只是讲用\(dfs\)怎么做一个小优化,不想看的可以跳过。
这个优化就是在处理如何维护贪吃蛇的位置(因为要防止贪吃蛇吃到自己)的问题上,如果每走一步都\(O(k)\)更新一遍会比较慢(虽然在\(k<=9\)的情况下也慢不了多少),所以我们打算每次通过\(O(1)\)来操作。
我们考虑为整个过程建一个时间,即贪吃蛇每走一格就时间\(+1\)秒,那么我们考虑定义一个数组\(time[i][j]\),表示格子\([i,j]\)什么时候是空的。
我们不妨将贪吃蛇看成很多段,每段是一格长,那么贪吃蛇的头就是第一段,尾就是最后一段。
那么当游戏开始时,贪吃蛇的最后一段(尾部)的格子肯定至少在\(1\)秒后才是空的,贪吃蛇的倒数第二段的格子肯定至少在\(2\)秒后才是空的(第\(1\)秒后,倒数第一段走到第\(1\)秒前倒数第二段的格子,第\(2\)秒后,倒数第一段离开)……贪吃蛇的第\(i\)段的格子肯定至少在\(k-i+1\)秒后才是空的……贪吃蛇的第\(1\)段的格子肯定至少在\(k\)秒后才是空的。(\(k\)的解释见题面)
对于每当贪吃蛇走一步维护\(time\)的问题,我们发现只有贪吃蛇的头走到的格子的\(time\)才会有变化,那么我们考虑,假设当前时间为\(t\)秒,贪吃蛇的头下一步要走到\([xi,yi]\)。
因为当前时间为\(t\)秒,贪吃蛇走到下一个格子需要\(1\)秒,然后等贪吃蛇完全经过需要\(k\)秒,所以\(time[xi][yi]=t+1+k\)秒,那么我们就能在\(O(1)\)的时间内维护贪吃蛇位置的变化了。
最后完整代码加注释如下:
#include<bits/stdc++.h>
#define N 20
#define K 15
#define INF 0x7fffffff
using namespace std;
struct data
{
int x,y,s;
};
int n,k,m,edx,edy,ans=INF,tim[N][N],snax[N],snay[N];
//edx、edy为终点的坐标
//snax[]、snay[]为贪吃蛇的每一段的坐标
int fx[]={-1,0,1,0},fy[]={0,1,0,-1};
char ch[N][N];
bool vis[N][N];//是否走过
bool check(int x,int y)
{
return x<1||x>n||y<1||y>m;
}
void dfs(int x,int y,int s,int t)
{
if(x==edx&&y==edy)
{
ans=min(ans,s);
return;
}
if(s>=ans)return;
for(int i=0;i<4;i++)
{
int xi=x+fx[i],yi=y+fy[i];
if(vis[xi][yi]||check(xi,yi)||ch[xi][yi]=='#'||tim[xi][yi]-t>1)continue;
int tt=tim[xi][yi];
tim[xi][yi]=t+k+1;//time值更新
vis[xi][yi]=true;//记录贪吃蛇来过这个位置,防止死循环
dfs(xi,yi,s+1,t+1);
vis[xi][yi]=false;//记得改回来哦
tim[xi][yi]=tt;
}
}
void bfs()
{
queue<data>q;
q.push((data){snax[1],snay[1],0});
while(!q.empty()&&(q.front().x!=edx||q.front().y!=edy))
{
data now=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int xi=now.x+fx[i],yi=now.y+fy[i];
if(vis[xi][yi]||check(xi,yi)||ch[xi][yi]=='#')continue;
vis[xi][yi]=true;
q.push((data){xi,yi,now.s+1});
}
}
if(q.empty())puts("-1");
else printf("%d\n",q.front().s);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",ch[i]+1);
for(int j=1;j<=m;j++)
{
if(ch[i][j]=='@')
{
edx=i,edy=j;
}
if('1'<=ch[i][j]&&ch[i][j]<='9')
{
snax[ch[i][j]-'0']=i,snay[ch[i][j]-'0']=j;
k=max(k,ch[i][j]-'0');
}
}
}
bool flag=true;
for(int i=0;i<4;i++)//特判终点的四周被堵住了
{
int xi=edx+fx[i];
int yi=edy+fy[i];
if(!check(xi,yi)&&ch[xi][yi]!='#')
{
flag=false;
break;
}
}
if(flag)
{
puts("-1");
return 0;
}
if(k==1)//特判k=1用bfs更快
{
bfs();
return 0;
}
for(int i=1;i<=k;i++)
tim[snax[i]][snay[i]]=k-i+1;//第0秒时的time
dfs(snax[1],snay[1],0,0);
if(ans!=INF)printf("%d\n",ans);
else puts("-1");
return 0;
}
总结
用时间复杂度高的算法时,要么想另一种做法,要么手造大数据测试并丧心病狂地卡常。
标签:yi,xi,格子,int,XSY2498,dfs,bfs,贪吃蛇 From: https://www.cnblogs.com/ez-lcw/p/16840598.html