Eight digits Ⅱ

    The difference between this question and the eight numbers is that one is the A* algorithm and the other is the IDA* algorithm. The essence is similar, but there are still some details that need to be considered.

        1. Valuation function: If you have a glance at the eight digits, you only need to know the final position of each symbol, so first preprocess the position of each character. Then, when looking up the estimated value of a certain state, you only need to find the Manhattan distance of all numbers from 0 to 8 to reach the final position. The sum of these Manhattan distances is the estimated value. If the position of 0~8 is correct, then X must be correct. s position.

        2. Optimization: Each location has four directions, one of which is the direction from the current location. Going back is equivalent to an invalid operation, so optimization that ignores invalid operations can be performed.

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = 1e3;
typedef long long ll;
typedef pair<int, int> pii;
int maxi, idx, dx[] = {1, 0, 0, -1}, dy[] = {0, -1, 1, 0}; 
string ed, be, p = "dlru";// 方向坐标是按字典序的,这样可以使找到的最小步数的字典序也是同步数最小的情况。
pii o[300];
char str[N];
int f(string a) // 估价函数,就是每个字符位置跟最终位置的曼哈顿距离,也就是当前字符要走到最终位置需要的最小步数。
{
    int s = 0;
    for (int i = 0; i < 9; i ++)
    if(a[i] != 'X') // 如果0~8都正确了,那X自然也就正确了。
        s += abs(i / 3 - o[a[i]].first) + abs(i % 3 - o[a[i]].second);
    return s;
}
int pp[N]; 
bool dfs(int x)
{
	if(x + f(be) > maxi) return false; // 当前深度加上最小估价 还大于目标步数,则直接结束
	if(be == ed) return true; // 到达终点 直接结束 返回状态
	int a, b;
	for(int i = 0; i < 9; i ++) // 获取X的位置的横纵坐标
		if(be[i] == 'X')
		{
			a = i / 3, b = i % 3;
			break;
		}
	for(int i = 0; i < 4; i ++) // 枚举方向
	{
		int a1 = a + dx[i], b1 = b + dy[i]; // X移动后的坐标	
		if(x && i + pp[x - 1] == 3) continue; // 优化:当天操作相当于回到上一个位置,那就跳过
		if(a1 < 0 || a1 > 2 || b1 < 0 || b1 > 2) continue; // 超出地图 跳过
		swap(be[a * 3 + b], be[a1 * 3 + b1]); // 移动X的位置
		str[x] = p[i]; // 记录当前行进方向
		pp[x] = i; // 记录行进方向下标,用来判断是否是回到原地
		if(dfs(x + 1)) // 向更深一层搜索
			return true;
		swap(be[a * 3 + b], be[a1 * 3 + b1]); // 还原场地
	}
	return false;
}
int main(void)
{
    IOS;
    int t, g = 1;
    cin >> t;
    while (t --)
    {
        cin >> be >> ed;
        idx = 0;
        for(int i = 0; i < 9; i ++) // 预处理,保存一下每个字符最终的位置。
            o[ed[i]] = {i / 3, i % 3};
		cout << "Case " << g ++ << ": ";
        for(maxi = 0; ; maxi ++) // IDA* 思想
            if(dfs(0))
                break;
        cout << maxi << endl;
        for(int i = 0 ; i < maxi; i ++) cout << str[i];
        cout << endl;
    }
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_64468032/article/details/130220093