一、问题描述
二、问题分析
书中的解题思路为用二维数组模拟,但是实际上我们只关注空白车位和目标车的位置,那么没有必要使用数组存储其他车的状态,只需要将空白车位和目标车的位置记录下来就可以,然后就是广度遍历,如Python实现。
另一种解题思路同样建立在以存储两点位置的基础上,对于空白车位的移动目标位置是有规律的,其必然会与目标车的当前位置相邻,且是靠近最终出口位置的,所以我们可以直接根据空白车位的移动规律设计代码,如C/C++实现。
三、代码实现
1.C/C++实现
#include <string>
#include <sstream>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cctype>
using namespace std;
typedef pair<int, int> Point;
bool point_swap(Point& p1, Point& p2)
{
// 判断是否可以交换(相邻点才可以互换)
if (abs(p1.first - p2.first) + abs(p1.second - p2.second) != 1)
return false;
swap(p1.first, p2.first);
swap(p1.second, p2.second);
return true;
}
int get_next_blank(Point& blank, const Point& cur, const Point& obj)
{
int v_det = (obj.second - cur.second > 0) ? 1 : -1;
int h_det = (obj.first - cur.first > 0) ? 1 : -1;
// 两个可能的最优点
Point tmp1 = make_pair(cur.first, cur.second + v_det);
Point tmp2 = make_pair(cur.first + h_det, cur.second);
// 计算两个新的空白点到原来位置的距离
int dis1, dis2;
if (cur.first == blank.first) // 三点一线的情况
dis1 = abs(blank.second - tmp1.second) + 2;
else
dis1 = abs(blank.second - tmp1.second) + abs(blank.first - tmp1.first);
if (cur.second == blank.second) // 三点一线的情况
dis2 = abs(blank.first - tmp2.first) + 2;
else
dis2 = abs(blank.first - tmp2.first) + abs(blank.second - tmp2.second);
// 贪心,选择最小距离
// 空白车位的两个候选位置与出口的距离基本上都是相同的,但是在最后一步时会有区别
if (dis1 + abs(obj.first - tmp1.first) + abs(obj.second - tmp1.second) >= dis2 + abs(obj.first - tmp2.first) + abs(obj.second - tmp2.second))
{
blank.first = tmp2.first;
blank.second = tmp2.second;
return dis2;
}
else
{
blank.first = tmp1.first;
blank.second = tmp1.second;
return dis1;
}
}
int main()
{
const int MAX_L = 10;
const int MAX_W = 10;
Point cur, obj, blank;
cur = make_pair(1, 1);
obj = make_pair(MAX_L, MAX_W);
blank = make_pair(MAX_L, MAX_W);
int steps = 0;
while (abs(obj.first - cur.first) + abs(obj.second - cur.second))
{
steps += get_next_blank(blank, cur, obj);
if (point_swap(cur, blank))
steps++;
}
cout << steps << endl;
return 0;
}
2.Python实现
# coding = utf-8
MAX_X = 10
MAX_Y = 10
history = [(1, 1, MAX_X, MAX_Y), ] # 存放遍历历史, 前两个值为目标车坐标,后两个值为空白位置坐标
history2level = [0, ] # 存放对应遍历的遍历深度
det_x = [0, 1, 0, -1]
det_y = [1, 0, -1, 0]
def get_next_level(index):
cur_level = history2level[index]
blank = history[index]
for i in range(4):
tmp_b = [blank[2] + det_x[i], blank[3] + det_y[i]]
if tmp_b[0] > 10 or tmp_b[1] > 10 or tmp_b[0] < 0 or tmp_b[1] < 0: # 越界
continue
if blank[0] == tmp_b[0] and blank[1] == tmp_b[1]: # 空白格移动到目标车,相当于两个位置交换
tmp_h = (blank[2], blank[3], tmp_b[0], tmp_b[1])
else:
tmp_h = (blank[0], blank[1], tmp_b[0], tmp_b[1])
if tmp_h not in history:
history.append(tmp_h)
history2level.append(cur_level + 1)
pass
def search():
index = 0
level = 0
while history[index][0] != MAX_X or history[index][1] != MAX_Y:
get_next_level(index)
index += 1
level = history2level[index]
return level
if __name__ == '__main__':
print(search())
pass