Curling 2.0
在MM-21星球上,今年的奥运会之后,冰壶越来越受欢迎。但规则与我们的规则有些不同。游戏在冰游戏板上进行,游戏板上标有方形网格。他们只使用一块石头。游戏的目的是以最少的动作将石头从开始引导到目标。
图1示出了游戏板的示例。一些正方形可能被块占用。有两个特殊的方块,即开始和目标,没有被块占用。(这两个方块是截然不同的。)一旦石头开始移动,它将继续运行,直到它碰到一个块。为了将石头带到目标,你可能不得不通过击打一块来阻止石头,然后再扔。
图1:电路板示例(S:开始,G:目标)
石头的运动遵循以下规则:
● 起初,石头静止在起始广场。
● 石头的运动受限于x和y方向。禁止对角线移动。
● 当石头静止不动时,你可以通过扔它来移动它。你可以把它扔到任何方向,除非它立即被阻止(图2(a))
● 一旦抛出,石头就会向同一方向移动,直到出现下列情况之一:
○ 石头击中一个块(图2(b),(c))。
◾ 石头停在它撞击的街区旁边的方块上。
◾ 块消失了。
○ 石头离开了游戏板。
◾ 游戏以失败告终。
○ 石头到达目标块。
◾ 石头停在那里,游戏成功结束。
● 你不能在游戏中扔石头超过10次。如果石头在10次移动中没有达到目标,则游戏以失败告终。
图2:石头运动
根据规则,我们想知道一开始的石头是否能达到目标,如果是,则需要求出最小的移动次数。
使用图1所示的初始配置,需要4次移动才能使石头从头到尾。路线如图3(a)所示。注意当石头到达目标时,板的配置已经改变,如图3(b)所示。
图3:图D-1的解决方案和最终的板配置
Input
输入是一系列数据集。输入的结尾由包含两个由空格分隔的零的线表示。数据集的数量永远不会超过100。
每个数据集的格式如下。
游戏板的宽度(= w)和游戏板的高度(= h)
游戏板的第一行
......
游戏板的第h行
板的宽度和高度满足:2 <= w <= 20,1 <= h <= 20。
每行包含由空格分隔的w十进制数。该数字描述了相应方块的状态。
0 空置方块
1 块
2 开始的位置
3 目标位置
图1的数据集如下:
6 6
1 0 0 2 1 0
1 1 0 0 0 0
0 0 0 0 0 3
0 0 0 0 0 0
1 0 0 0 0 1
0 1 1 1 1 1
Output
对于每个数据集,打印一个十进制整数的行,表示从开始到目标的路径上的最小移动次数。如果没有这样的路线,请改为打印-1。除了这个数字,每行不应该有任何字符。
Sample Input
2 1
3 2
6 6
1 0 0 2 1 0
1 1 0 0 0 0
0 0 0 0 0 3
0 0 0 0 0 0
1 0 0 0 0 1
0 1 1 1 1 1
6 1
1 1 2 1 1 3
6 1
1 0 2 1 1 3
12 1
2 0 1 1 1 1 1 1 1 1 3
13 1
2 0 1 1 1 1 1 1 1 1 1 1 3
0 0
Sample Output
1
4
-1
4
10
-1
C++编写:
这道题也是深度优先搜索.
//w表示列数,h表示行数
#include<iostream>
using namespace std;
const int MAX=20;
int board[MAX+1][MAX+1];
int sx,sy; //用于记录起点坐标
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
int w,h,steps; //steps为最小移动次数
bool check(int x,int y)
{
if(x>=0 && x<h && y>=0 &&y<w) return 1;
else return 0;
}
void dfs(int x,int y,int step)
{
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
int nx1,ny1;
if(step<steps-1 && check(nx,ny) && board[nx][ny]!=1)
{
while(check(nx,ny)&&board[nx][ny]==0)
{
nx += dx[i];
ny += dy[i];
}
if(check(nx,ny))
{
if(board[nx][ny] == 3)
steps=step+1;
if(board[nx][ny] == 1)
{
board[nx][ny] = 0;
dfs(nx-dx[i],ny-dy[i],step+1);
board[nx][ny] = 1;
}
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>w>>h)
{
if(w==0 && h==0)
break;
steps = 11;
for(int i=0;i<h;i++)
{
for(int j=0;j<w;j++)
{
cin>>board[i][j];
if(board[i][j] == 2) //记录起点坐标
{
sx=i;
sy=j;
board[i][j]=0; //将起点坐标的值换成0
}
}
}
dfs(sx,sy,0);
steps=steps<11?steps:-1;
cout<<steps<<endl;
}
}