题目链接: POJ 3009-Curling 2.0
题目大意:
在有砖块的场地打冰球,要从把冰球从S打到G,球只能在x,y轴方向运动,只能向有空位置的地方击球。比如图a, 只能向上和向右击球。击球后,球会一直沿着击球方向运动,直到撞到砖块,或者出界。如果撞到砖块,则砖块消失,球停下来。像图b,c这样。如果出界,则游戏结束。最多只能击球10下。10下之后还没有到达G,则游戏结束。现在要找能够从S到G的需要的最小的击球次数。
题解:
dfs, 搜索10层, 每次至多有4个方向可以选择。搜索完要回溯。出界则直接退出。
代码:
#include <iostream>
#include <cstring>
using namespace std;
int Min = 0xffffff;
int a[30][30], w, h;
int sx, sy;
bool dfs(int x, int y, int step) {
if (step > 10) return false;
//cout << x << " " << y << endl;
for (int dir = 0; dir < 4; dir++) { // 顺时针枚举4个方向
int tx, ty;
if (dir == 0) { // 向上
tx = x, ty = y;
//朝上走,直到越界或者撞到砖头
while (tx-1 >= 0 && !a[tx-1][ty]) tx--;
if (tx > 0) { //如果没越界
if (a[tx-1][ty] == 3) { //到达G
Min = min(Min, step);
return true;
}
//如果在这个方向上有走动(必须有走动,才能把砖头撞消失)
if (tx != x) {
a[tx-1][ty] = 0;
dfs(tx, ty, step+1);
a[tx-1][ty] = 1;//回溯
}
}
}
else if (dir == 1) { // 向右
tx = x, ty = y;
while (ty+1 <= w+1 && !a[tx][ty+1]) ty++;
if (ty <= w) {
if (a[tx][ty+1] == 3) {
Min = min(Min, step);
return true;
}
if (ty != y) {
a[tx][ty+1] = 0;
dfs(tx, ty, step+1);
a[tx][ty+1] = 1;
}
}
}
else if (dir == 2) { // 向下
tx = x, ty = y;
while (tx+1 <= h+1 && !a[tx+1][ty]) tx++;
if (tx <= h) {
if (a[tx+1][ty] == 3) {
Min = min(Min, step);
return true;
}
if (tx != x) {
a[tx+1][ty] = 0;
dfs(tx, ty, step+1);
a[tx+1][ty] = 1;
}
}
}
else if (dir == 3) { // 向右
tx = x, ty = y;
while (ty-1 >= 0 && !a[tx][ty-1]) ty--;
if (ty > 0) {
if (a[tx][ty-1] == 3) {
Min = min(Min, step);
return true;
}
if (ty != y) {
a[tx][ty-1] = 0;
dfs(tx, ty, step+1);
a[tx][ty-1] = 1;
}
}
}
}
}
int main() {
while(cin >> w >> h) {
if (w == 0 && h == 0) break;
Min = 0xfffffff;
memset(a, 0, sizeof(a));
for (int i = 1; i <= h; i++)
for (int j = 1; j <= w; j++){
cin >> a[i][j];
if (a[i][j] == 2) {
sx = i; sy = j;
a[i][j] = 0;
}
}
dfs(sx, sy, 1);
if (Min == 0xfffffff) cout << -1 << endl;
else cout << Min << endl;
}
return 0;
}