算法趣题-Q26

一、问题描述

二、问题分析

        书中的解题思路为用二维数组模拟,但是实际上我们只关注空白车位和目标车的位置,那么没有必要使用数组存储其他车的状态,只需要将空白车位和目标车的位置记录下来就可以,然后就是广度遍历,如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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值