UVA652 Eight题解

时间:2021-07-14
本文章向大家介绍UVA652 Eight题解,主要包括UVA652 Eight题解使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目

UVA652 Eight
洛谷链接
[https://www.luogu.com.cn/problem/UVA652]

思路

  • 判断是否 unsolvable:

    有大佬分析过,对于奇数边的瓷砖问题,如果源状态和目标状态的逆序数的奇偶性相同, 则状态可达.
    所以我们可以通过判断输入状态的逆序数奇偶性,来直接判断是否 unsolvable

  • 如何设计估价函数

    影响估价函数的因素有两个:

    \(h(x)\) : 当前状态的混乱程度(用各个数偏离其应在位置的程度表示)

    \(g(x)\) : 达到该状态已用步数(通过查询map实现)

    估价函数 \(f(x) = h(x) + g(x)\)

  • 如何记录路径

    通过一个map<string,string> opt_map 实现

    其中 key 是状态, value 是达到该状态所走过的路径,用字符串记录

    ** 当搜索时发现目前状态的路径长度小于已有的长度时进行更新,以保证达到该状态的路径最短

代码

#include <iostream>
#include <queue>
#include <cstdlib>
#include <map>
using namespace std;

map<string, string> opt_map;

class status
{
public:
	string str;			//表示当前状态
	int price;			//表示当前状态的估价

	bool const operator < (const status b) const		//重载小于号,使估价小的优先
	{
		return price > b.price;
	}

	status(string s)
	{
		str = s;
		price = 0;
		//计算混乱程度
		for (int t(0); t < 9; ++t)
		{
			char c = s[t];
			if (c != 'x')
			{
				int i = c - '1';
				price += abs((int)(i / 3 - t / 3)) + abs((int)(i % 3 - t % 3));
			}
		}
		//计算达到该状态的路径长度
		if (opt_map.find(s) == opt_map.end())
			price += 0;
		else
			price += opt_map.at(s).length();
	}
};

priority_queue<status> q;

//opt函数用于状态转移,若转移失败(不满足条件)则返回源状态
string opt(string ori, char type)
{
	size_t x = ori.find_first_of('x');
	switch (type)
	{
	case 'u':
		if (x >= 3 && x != string::npos)
			swap(ori.at(x), ori.at(x - 3));
		break;
	case 'd':
		if (x < 6 && x != string::npos)
			swap(ori.at(x), ori.at(x + 3));
		break;
	case 'l':
		if (x != 0 && x != 3 && x != 6 && x != string::npos)
			swap(ori.at(x), ori.at(x - 1));
		break;
	case 'r':
		if (x != 2 && x != 5 && x != 8 && x != string::npos)
			swap(ori.at(x), ori.at(x + 1));
		break;
	}
	return ori;
}

char option[5] = "uldr";

bool A_star(string ori)
{
	while (!q.empty())
		q.pop();

	opt_map.insert({ori, ""});
	q.push(ori);

	while (!q.empty())
	{
		status cur = q.top();		//从优先队列中获取源状态
		q.pop();

		if (cur.str == "12345678x")
		{
			cout << opt_map.at("12345678x");
			return true;
		}
		//获取原状态的搜索路径长度 及 搜索路径
		int cost = opt_map.at(cur.str).length();
		string curopt = opt_map.at(cur.str);

		string tar;
		for (int i(0); i < 4; ++i)
		{
			tar = opt(cur.str, option[i]);	//获取目标状态
			if (tar != cur.str)
			{
                //判断 是否达到过目标状态 以及 之前搜索到的路径是否更长
				if (opt_map.find(tar) == opt_map.end() || cost + 1 < opt_map.at(tar).length())
				{
					opt_map[tar] = curopt + option[i];	//将当前进行的操作加到源状态的操作后面并更新目标状态
					q.push(tar);
				}
			}
		}
	}
	return false;
}

int main()
{
	int n(0);
	cin >> n;
	while (n--)
	{
		char num[9] = {0};

		string str = "";
		for (int i(0); i < 9; ++i)
		{
			cin >> num[i];
			str = str + num[i];
		}

		int rev(0);

		for (int i(0); i < 9; ++i)
			for (int j(i); j < 9; ++j)
				if (num[i] != 'x' && num[j] != 'x' && num[i] > num[j])
					rev++;

		if (rev & 1)
			cout << "unsolvable" << endl;
		else
			A_star(str);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/SirlyDreamer/p/15009976.html