题目链接:
http://poj.org/problem?id=3009
大致题意:
就是要求把一个冰壶从起点“2”用最少的步数移动到终点“3”,其中0为移动区域,1为石头区域,冰壶一旦想着某个方向运动就不会停止,也不会改变方向(想想冰壶在冰上滑动),除非冰壶撞到石头1 或者 到达终点 3。
解题思路:
所谓的“走一步”,就是指冰壶从一个静止状态到下一个静止状态,就是说冰壶在运动时经过的“格数”不视作“步数”,也就是说冰壶每次移动的距离都是不定的。还有就是由于石头会因为冰壶的碰撞而消失,因此冰壶每“走一步”,场地的环境就会改变一次。
AC代码:
#include<iostream>
using namespace std;
typedef class
{
public:
int x;//冰壶当前的位置
int y;
bool status;//false为静止
} chess;
const int inf =11;
chess s, e; //冰壶的起止点
int w, h; //场地的宽和高
int ans;
int board[30][30];
void dfs(int x, int y, bool status, int direction, int step, bool flag)
{
//direction是指冰壶当前的运动方向:N-0 W-1 S-2 E-3
//flag:是否消除direction方向下一格位置的石头
if(step > 10)
return;
if(board[x][y] == 3) {
//终点
if(ans > step)
ans = step;
return;
}
if(flag) {
//消除石头
switch(direction) {
case 0: {
board[x - 1][y] = 0;
break;
}
case 1: {
board[x][y - 1] = 0;
break;
}
case 2: {
board[x + 1][y] = 0;
break;
}
case 3: {
board[x][y + 1] = 0;
break;
}
}
}
if(!status) { //静止
//向北运动
if(x - 1 >= 1 && (board[x - 1][y] == 0 || board[x - 1][y] == 3))
dfs(x - 1, y, true, 0, step + 1, false);
//向西运动
if(y - 1 >= 1 && (board[x][y - 1] == 0 || board[x][y - 1] == 3))
dfs(x, y - 1, true, 1, step + 1, false);
//向南运动
if(x + 1 <= h && (board[x + 1][y] == 0 || board[x + 1][y] == 3))
dfs(x + 1, y, true, 2, step + 1, false);
//向东运动
if(y + 1 <= w && (board[x][y + 1] == 0 || board[x][y + 1] == 3))
dfs(x, y - 1, true, 3, step + 1, false);
} else if(status) {
switch(direction) {
case 0: {
if(x - 1 < 1)
return ;
else {
if(board[x - 1][y] == 0) //下一位置为0且不越界,继续运动
dfs(x - 1, y, true, 0, step, false);
else if(board[x - 1][y] == 1)
dfs(x, y, false, 0, step, true); //下一位置为1且不越界,停止运动,并消除下一位置的石头
else if(board[x - 1][y] == 3)
dfs(x - 1, y, false, 0, step, false);
}
break;
}
case 1: {
if(y - 1 < 1)
return ;
else {
if(board[x][y - 1] == 0) //下一位置为1且不越界,继续运动
dfs(x, y - 1, true, 1, step, false);
else if(board[x][y - 1] == 1)
dfs(x, y, false, 1, step, true); //下一位置为1且不越界,停止运动,并消除下一位置的石头
else if(board[x][y - 1] == 3)
dfs(x, y - 1, false, 1, step, false);
}
break;
}
case 2: {
if(x + 1 > h)
return ;
else {
if(board[x + 1][y] == 0) //下一位置为2且不越界,继续运动
dfs(x + 1, y, true, 2, step, false);
else if(board[x + 1][y] == 1)
dfs(x, y, false, 2, step, true); //下一位置为1且不越界,停止运动,并消除下一位置的石头
else if(board[x + 1][y] == 3)
dfs(x + 1, y, false, 2, step, false);
}
break;
}
case 3: {
if(y + 1 > w)
return ;
else {
if(board[x][y + 1] == 0) //下一位置为3且不越界,继续运动
dfs(x, y + 1, true, 3, step, false);
else if(board[x][y + 1] == 1)
dfs(x, y, false, 3, step, true); //下一位置为1且不越界,停止运动,并消除下一位置的石头
else if(board[x][y + 1] == 3)
dfs(x, y + 1, false, 3, step, false);
}
break;
}
}
}
if(flag) { //回溯前还原石头,即还原上一步的棋盘状态
switch(direction) {
case 0: {
board[x - 1][y] = 1;
break;
}
case 1: {
board[x][y - 1] = 1;
break;
}
case 2: {
board[x + 1][y] = 1;
break;
}
case 3: {
board[x][y + 1] = 1;
break;
}
}
}
return ;
}
int main()
{
while(cin >> w >> h)
{
if(!w && !h)
break;
ans = inf;
for(int i = 1; i <= h; i++) {
for(int j = 1; j <= w; j++) {
cin >> board[i][j];
if(board[i][j] == 2) {
s.x = i;
s.y = j;
s.status = false;
board[i][j] = 0;
}
if(board[i][j] == 3) {
e.x = i;
e.y = j;
}
}
}
dfs(s.x, s.y, s.status, 0, 0, false);
if(ans <= 10)
cout << ans << endl;
else
cout << -1 << endl;
}
return 0;
}