挑战程序设计竞赛 2.1章习题 POJ 3009 Curling 2.0
https://vjudge.net/problem/POJ-3009
在 MM-21 星球上,今年的奥运会之后,冰壶运动开始流行起来。但规则与我们的有些不同。冰壶比赛是在一块冰板上进行的,冰板上标有方形网眼。
他们只使用一块石头。游戏的目的是用最少的步数将石头从起点引向终点。
图 1 显示了游戏棋盘的一个示例。一些方格可能被积木占据。有两个特殊的方格,即起点和目标方格,这两个方格没有积木。(这两个方格是不同的。)
一旦棋子开始移动,它就会一直走下去,直到碰到一个积木为止。为了让石子到达目标,你可能需要让石子停下来,撞上一个木块,然后再扔一次。
图 1:棋盘示例(S:起点,G:终点)
石子的移动遵循以下规则:
开始时,石子静止在起点方格。
石子的移动仅限于 x 和 y 方向。禁止对角线移动。
当石块静止不动时,您可以通过投掷使其移动。您可以将它扔向任何方向,除非它立即被挡住(图 2(a))。
投掷后,石子会一直向同一方向移动,直到出现以下情况之一:
石子击中一个木块(图 2(b)、(c))。
石块停在被击中石块旁边的方格。
木块消失。
棋子离开棋盘。
游戏以失败告终。
石子到达目标方格。
石子停在目标方格,游戏以成功结束。
一局游戏中投掷石块的次数不能超过 10 次。如果石子在 10 次移动中没有到达目标位置,则游戏以失败告终。
图 2:石子移动
根据规则,我们想知道石头在开始时是否能到达目标,如果能,则需要最少的移动次数。
按照图 1 所示的初始配置,需要走 4 步棋才能将石子从起点带到终点。路线如图 3(a) 所示。注意,当棋子到达终点时,棋盘的配置发生了变化,如图 3(b)所示。
输入是一系列数据集。输入结束时,会出现一行包含两个 0 的空格。数据集的数量永远不会超过 100 个。
每个数据集的格式如下。
电路板的宽度(=w)和高度(=h)
棋盘第一行
...
棋盘的第 h 行
黑板的宽度和高度满足以下条件: 2 <= w <= 20,1 <= h <= 20。
每行由 w 个十进制数字组成,以空格分隔。数字描述了相应方格的状态。
0 空方格
1 块
2 开始位置
3 目标位置
The dataset for Fig. D-1 is as follows:
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
输出
对于每个数据集,打印一行十进制整数,表示从起点到目标的最小移动次数。如果没有这样的路线,则打印-1。每一行中除该数字外不得有任何其他字符。
输入
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 1 3
13 1
2 0 1 1 1 1 1 1 1 1 1 1 3
14 6
0 0 1 0 0 0 0 1 1 0 1 1 1 0
0 0 1 0 1 0 1 1 1 1 1 1 1 1
1 1 0 2 1 1 0 0 1 0 0 0 0 1
1 0 1 1 1 1 1 1 1 1 1 1 1 0
1 0 1 1 1 0 1 1 0 1 1 0 0 0
1 0 1 0 0 1 0 0 1 0 0 0 0 3
4 8
0 1 0 0
0 0 0 0
1 0 0 1
0 0 0 0
0 0 0 0
3 0 1 0
1 0 1 0
1 0 0 2
0 0
输出
1
4
-1
4
10
-1
根据题意
本来可以考虑使用BFS 查看10回合以内覆盖的范围。
但是每次移动后,碰到冰壁会损坏墙壁,状态是变化的。BFS不方便记录。
所以 考虑DFS10回合内的所有移动,更加方便。
注意两点
1 通过目标位置即可 不用停留在目标位置上
2 紧贴墙壁不能向墙壁方向前进 需要有空地加速
代码如下
#include <iostream>
#include <queue>
#include <cstring>
//https://vjudge.net/problem/POJ-3009
using namespace std;
const int N = 22;
int gra[N][N];
int w, h, startx, starty;
int ans = 0x3f3f3f3f;
void dfs(int x, int y, int step);
void change(int x, int y, int addx, int addy, int step) {
int newx = x + addx; int newy = y + addy;
if (newx >= 0 && newx < h && newy >= 0 && newy < w && gra[newx][newy] == 1) {
//不能往这个方向移动
return;
}
if (newx < 0 || newx >= h || newy < 0 || newy >= w) {
//滑出街 不能移动
return;
}
x += addx, y += addy;
//开始滑动
while (x >= 0 && x < h && y >= 0 && y < w) {
if (gra[x][y] == 3) {
ans = min(step+1, ans);
return;
}
else if (gra[x][y] == 1) {
gra[x][y] = 0;
dfs(x-addx, y-addy, step + 1);
gra[x][y] = 1; return;
}
x += addx, y += addy;
}
}
void dfs(int x, int y, int step) {
//向四个方向滑动
if (step > 10) return;
change(x, y, 0, 1, step);
change(x, y, 0, -1, step);
change(x, y, 1, 0, step);
change(x, y, -1, 0, step);
return ;
}
void solve() {
ans = 0x3f3f3f3f;
dfs(startx,starty,0);
if (ans > 10) ans = -1;
cout << ans << endl;
}
int main() {
while (cin >> w >> h) {
if (w == 0 && h == 0)break;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
cin >> gra[i][j];
if (gra[i][j] == 2) {
startx = i; starty = j;
}
}
}
solve();
}
return 0;
}
作 者: itdef
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力
![阿里打赏](https://files.cnblogs.com/files/itdef/ali2.bmp)
![微信打赏](https://files.cnblogs.com/files/itdef/weixin2.bmp)