今年的奥运会之后,在行星mm-21上冰壶越来越受欢迎。但是规则和我们的有点不同。这个游戏是在一个冰游戏板上玩的,上面有一个正方形网格。他们只用一块石头。游戏的目的是让石子从起点到终点,并且移动的次数最小
图1显示了一个游戏板的例子。一些正方形格子可能被砖块占据。有两个特殊的格子,起始点和目标点,这是不占用块。(这两个方块是不同的)一旦石头开始移动就不会停下,除非它击中砖块块。为了使石头到达终点,你可以通过让石块击中墙壁或者砖块来停下
图1:例子(S:开始,G:目标)
石头的运动遵循以下规则:
- 开始时,石头静止起点广场上。
- 石头的运动仅限于x和y方向。禁止对角线移动。
- 当石头静止时,你可以让他向任意方向移动,除非它移动的方向上有砖块(图2(a))。
- 一旦抛出,石头不断向同一方向移动,直到下列事件之一发生:
- 石头击中砖块(图2(b),(c))。.
- 石头停在他击中的砖块之前
- 被击中的砖块消失
- 石块飞出游戏板之外。
- 游戏结束的条件
- 到达目标点
- 石头停在目标点游戏成功
- 石头击中砖块(图2(b),(c))。.
- 不能在十步之内到达目标点则返回失败。
Fig. 2: Stone movements
通过这些规则我们想知道,石头是否能够到达目标点和最少移动次数
初始配置如图1所示,石头从开始到目标需要4次移动。路线如图3所示(a)。注意当石头到达目标时,游戏版的配置如图3(b)改变。
图3:图1的解决方案和解决之后的结果。
这道题和以往的起点到终点的最短步数,有点区别;
以往的是起点到终点一个bfs就行了;这题是从起点开始每走一个方向,只有碰到障碍物或超出地图边界才会停下,因此推荐使用dfs,因为每当石头碰到障碍物的同时障碍也会消失(在搜索的时候可能有几条路,所以需要障碍物重建),要注意这点,但要是当石头停下,去搜索周围的时候,发现周围都是障碍物,则停止搜索举个栗子(偷个懒,就拿题目样例来说)
1 2 3 4 5 6(下标,初始位置为3)
1 0 2 1 1 3(往左看,有一个0,说明可以走,走到2的位置停下,1位置上的1消失)
0 0 2 1 1 3(把2看作0,往右看,可以走,走到位置3停下,位置4的1消失)
0 0 2 0 1 3(在走到位置4停下,位置5的1消失)
0 0 2 0 0 3(再走到终点)
0 0 2 0 0 3
总共4步,这是一种情况,再说另一种类似的情况
1 2 3 4 5 6(同上)
1 1 2 1 1 3(发现初始位置左右都是1,所以这种情况走不了,因此输出-1,就行)
还有一个小坑(我的小坑,wa好多次),就是题目向输入列再输入行
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 50;
int Map[maxn][maxn],vis[maxn][maxn];
int n,m,sx,sy,flag,ans;
int dr[]={1,0,-1,0};
int dc[]={0,-1,0,1};
void dfs(int x,int y,int st){
int dx,dy,xx,yy;
if(Map[x][y]==3){
ans=min(ans,st);
return;
}
if(st>10)return;
for(int i=0;i<4;i++){
dx=x+dr[i];
dy=y+dc[i];
xx=x;
yy=y;
while(dx>0&&dx<=n&&dy>0&&dy<=m&&Map[dx][dy]!=1){
xx+=dr[i];
yy+=dc[i];
if(Map[xx][yy]==3){
ans=min(ans,st);
return;
}
dx=xx+dr[i];
dy=yy+dc[i];
if(dx<1||dx>n||dy<1||dy>m)break;
if(Map[dx][dy]==1){
Map[dx][dy]=0;
dfs(xx,yy,st+1);
Map[dx][dy]=1;
}
}
}
}
int main(){
while(~scanf("%d%d",&m,&n)&&m&&n){
memset(Map,0,sizeof(Map));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&Map[i][j]);
if(Map[i][j]==2){
sx=i;sy=j;
}
}
}
ans=401;
dfs(sx,sy,1);
if(ans>10)cout<<"-1"<<endl;
else cout<<ans<<endl;
}
}