马里奥 (HG 2018.10.5 T1)

hicc0305

2018-10-05 14:45:36

Personal

### 题目大意: 给一个n*m的图,只有'#'和'_','_'是空气,'#'是方块,你一下开始站在最下层(保证最下层都是'#') ,你可以在连续的#上左右移动,上下垂直移动时需要梯子,上下高度差不超过梯子长度的方块可以随意上下。求梯子的最小长度。 ### 样例: 输入: ``` 5 8 ####____ ___#_### ###__#__ ______#_ ######## 2 4 ``` 输出: 2 ### 数据范围: 1≤n,m≤1,000,1≤x≤n,1≤y≤m。 那么怎么做呢。。答案是。。爆搜! dfs会爆栈,要用bfs,搜的时候,记录一下走到现在的梯子用过的最小长度。然后开一个dis数组,表示所有走到x,y这个点的情况中最短的梯子长度。像spfa一样,如果要去的点梯子长度已经还要短了就不走了。具体看代码 ``` #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n,m,ux,uy; int dis[1100][1100]; int det[5][3]={{1,0},{0,1},{-1,0},{0,-1}}; char a[1100][1100]; struct Node { int x,y,z; }q[10000100],u,v; void bfs(int x,int y,int z) { u.x=x,u.y=y,u.z=0,q[1]=u; int l=0,r=1; while(l<r) { u=q[++l]; for(int i=0;i<4;i++) { v.x=u.x+det[i][0],v.y=u.y+det[i][1],v.z=u.z; if(v.x<1 || v.x>n || v.y<1 || v.y>m) continue; if(i%2)//往左右走 { if(a[v.x][v.y]=='_') continue; if(dis[v.x][v.y]<=v.z) continue; dis[v.x][v.y]=v.z; q[++r]=v; } else//上下爬 { int l=1; while(a[v.x][v.y]=='_' && v.x+det[i][0]>=1 && v.x+det[i][0]<=n) l++,v.x+=det[i][0]; if(a[v.x][v.y]=='_' || v.x<1 || v.y>n) continue; v.z=max(l,v.z); if(dis[v.x][v.y]<=v.z) continue; dis[v.x][v.y]=v.z; q[++r]=v; } } } } int main() { memset(dis,0x7f,sizeof(dis)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%s",a[i]+1); scanf("%d%d",&ux,&uy); dis[n][m]=0; bfs(n,1,0); printf("%d",dis[ux][uy]); return 0; } ```