hdu 3567 EightⅡ(映射+bfs暴力打表)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39562952/article/details/82881943

思路:跟hdu 1043 其实差不多,只是最后的状态变成了非唯一情况;我们要做的就是把最后的状态变成唯一的或者唯几的情况;

看了网上大佬的思路之后发现,不管最后的状态怎么变化,都可以映射成9种,也就是X放在其中的9个位置,然后按照映射关系把起始状态也映射一下,最后两个映射的达到路径跟要求的路径其实是一样的(虽然不知道为什么,但是事实如此);

因为有9种情况,那么就有9张表分别代表到达9个末位置的路径;

怎么保证是字典序最小的话,只要搜素方向是:dlru就行了;

代码如下:

#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <cstring>
#include <climits>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stdio.h>
#include <sstream>
#include <map>
#define esp 1e-4
using namespace std;
/*8数码进阶问题,把终点映射成9种情况,分别对应x的9个位置,然后打出9种位置的表
(即各种点到终点的路径)
*/
char inti[9][10] =
{
	"912345678",
	"192345678",
	"129345678",
	"123945678",
	"123495678",
	"123459678",
	"123456978",
	"123456798",
	"123456789",
};
int fac[] = { 1,1,2,6,24,120,720,5040,40320 };//0-8的阶乘 
int then[4][2] = { {1,0},{0,-1},{0,1},{-1,0} };//代表向下,向左,向右,向上 ,因为要字典序最小,所有dlru
struct node1//路径点 
{
	int f;// 
	char way;//代表到达这个点的走法 
};
node1 path[9][400000];//9种情况
struct node2//bfs中queue中的点 
{
	char a[10];
	int ktval;
	int n;//x在该状态下的位置	
};
int kt(char *a)//计算康托展开的值 
{
	int ans = 0;
	for (int i = 0; i < 9; i++)
	{
		int k = 0;
		for (int j = i + 1; j < 9; j++)
		{
			if (a[i] > a[j])
				k++;
		}
		ans += k * fac[8 - i];
	}
	return ans;
}
void bfs(char a[10], int pos)
{
	int ktval = kt(a);
	queue<node2> q;
	node2 temp;
	strcpy(temp.a, a);
	temp.ktval = ktval;
	temp.n = pos;
	q.push(temp);
	path[pos][ktval].f = 0;
	while (!q.empty())
	{
		for (int i = 0; i < 4; i++)
		{
			int nx = q.front().n / 3 + then[i][0];//行 
			int ny = q.front().n % 3 + then[i][1];//列
			int	nn = nx * 3 + ny;//下个位置
			if (nx < 0 || nx >= 3 || ny < 0 || ny >= 3)
				continue;
			temp = q.front();
			swap(temp.a[nn], temp.a[q.front().n]);
			ktval = kt(temp.a);
			if (path[pos][ktval].f == -1)//没访问过 
			{
				temp.ktval = ktval;
				temp.n = nn;
				q.push(temp);
				path[pos][ktval].f = q.front().ktval;
				if (i == 0) path[pos][ktval].way = 'd';
				if (i == 1) path[pos][ktval].way = 'l';
				if (i == 2) path[pos][ktval].way = 'r';
				if (i == 3) path[pos][ktval].way = 'u';
			}
		}
		q.pop();
	}
}
int main()
{
	for (int i = 0; i < 9; i++)
	{
		for (int j = 0; j < 400000; j++)
		{
			path[i][j].f = -1;//代表没访问过 
		}
	}
	for (int i = 0; i < 9; i++)
	{
		bfs(inti[i], i);
	}

	int T;
	cin >> T;
	char s1[10];
	char s2[10];
	int pos;//代表要达到的状态种x的位置 
	for (int ca = 1; ca <= T; ca++)
	{
		cin >> s2 >> s1;
		printf("Case %d:", ca);
		for (int i = 0; i < 9; i++)
		{
			if (s1[i] == 'X')
			{
				s1[i] = '9';
			}
			if (s2[i] == 'X')
			{
				s2[i] = '9';
				pos = i;
			}
		}
		int a[10];//代表映射关系:i--a[i]
		int x = 1;
		for (int i = 0; i < 9; i++)
		{
			if (s2[i] == '9')
				continue;
			a[s2[i] - '0'] = x;
			x++;
		}
		for (int i = 0; i < 9; i++)
		{
			if (s1[i] == '9')
				continue;
			s1[i] = a[s1[i] - '0'] + '0';
		}
		//cout << s1 << endl;
		int ktval = kt(s1);
		int endktval = kt(inti[pos]);
		int ans = 0;
		char ansc[10000];
		if(path[pos][ktval].f==-1)
		{
			cout <<" 0" << endl;
			continue;
		}
		while (ktval != endktval)
		{
			ansc[ans++] = path[pos][ktval].way;
			ktval = path[pos][ktval].f;

		}
		
		cout <<" "<< ans << endl;
		for(int i=ans-1;i>=0;i--)
			cout << ansc[i];
		cout<<endl;
	}
	return 0;
	/*
22222
564178X23
7568X4123
87654321X 321X45678
	*/
}

猜你喜欢

转载自blog.csdn.net/qq_39562952/article/details/82881943