题解——八数码难题

思路

由明确的两种状态可以想到

D(double)BFS即双向BFS

输入的是个

283104765

然而 凡是搜索都有个标记即vis[]

但 按题意3 * 3的地图不好标记(也许用map可以)

于是直接用一维dir数组改成

int dir[4] = {1,-3,-1,3};

但九位数也是开不了的

就有一个cantor展开式

状态压缩一下

inline int cantor(int a[])
{
	int i,j,ans = 0;
	for(i = 0;i < 9;i++)
	{
		int s = 0;
		for(j = i + 1;j < 9;j++)
			if(a[j] < a[i]) s++;
		ans += s * fac[8 - i];
	}
	return ans;
}

然后就行了 DBFS直接套板子啊

优化

其实就上面的好像就可以过了

但还有个优化

逆序对有关

将3 * 3 的图 弄成序列

可以得出结论:初始状态的逆序对模2必须等于目标状态的逆序对模2,否则无法达成,输出-1

证明

可以转为 初始状态无论如何改变其奇偶性不变

位置图

1 2 3

4 5 6

7 8 9

将3 * 3 的图 弄成序列

1 2 3 4 5 6 7 8 9

注意 0 不算入队列 所以上面实际上是8个

~~

2 8 3

1 0 4

7 6 5

可见 当位置5的0与位置8的6交换会有几种情况

位置n的数 为方便简写为(n)

Case1:(6)和(7)中有0个比(8)小

则逆序对+ 2

Case2:(6)和(7)中有1个比(8)小

则逆序对- 1 + 1

Case2:(6)和(7)中有2个比(8)小

则逆序对+ 2

综上逆序对奇偶性不变

其它交换情况可以类似讨论

代码

#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int MAXN = 400000;
int step[2][MAXN],fac[10] = {1,1,2,6,24,120,720,5040,40320,362880};
bool vis[2][MAXN];
int dir[4] = {1,-3,-1,3};

//cantor状态压缩
inline int cantor(int a[])
{
	int i,j,ans = 0;
	for(i = 0;i < 9;i++)
	{
		int s = 0;
		for(j = i + 1;j < 9;j++)
			if(a[j] < a[i]) s++;
		ans += s * fac[8 - i];
	}
	return ans;
}
struct Node
{
	int word[9],loc,ca;
	bool f;
	void node(int Word[],int LOC,int CA,bool F)
	{
		for(int i = 0;i < 9;i++) word[i] = Word[i];
		loc = LOC,ca = CA,f = F;
	}
}Start,order;
inline int dbfs()
{
	queue<Node> q;
	Start.f = 1,order.f = 0;
	q.push(Start);
	q.push(order);
	int i;
	while(!q.empty())
	{
		Node tmp = q.front();
		q.pop();
		if(vis[!tmp.f][tmp.ca])
			return (step[1][tmp.ca] + step[0][tmp.ca]);
		int Step = step[tmp.f][tmp.ca];
		for(i = 0;i < 4;i++)
		{
			int poss = tmp.loc + dir[i];
            
            //由于dir数组改了 判断也得改
			if(0 <= poss&&poss < 9&&(tmp.loc % 3 == poss % 3||tmp.loc / 3 == poss / 3))
			{
				swap(tmp.word[tmp.loc],tmp.word[poss]);
				int nca = cantor(tmp.word);
				if(!vis[tmp.f][nca])
				{
					Node g;
					vis[tmp.f][nca] = 1;
					step[tmp.f][nca] = Step + 1;
					g.node(tmp.word,poss,nca,tmp.f);
					q.push(g);
				}
				swap(tmp.word[tmp.loc],tmp.word[poss]);	
			}
		}
	}
	return -1;
}

//优化 求逆序对
inline int cutdown(int a[])
{
	int i,j,q = 0;
	for(i = 0;i < 9;i++)
		for(j = i + 1;j < 9;j++)
			if(a[i] != 0&&a[j] != 0&&a[j] < a[i]) q++;
	return q;
}
int main()
{
	int i;
	for(i = 0;i < 9;i++) 
	{
		scanf("%d",&Start.word[i]);
		if(!Start.word[i]) Start.loc = i;
	}
	for(i = 0;i < 9;i++)
	{
		scanf("%d",&order.word[i]);
		if(!order.word[i]) order.loc = i;
	}
    //优化
	if(cutdown(Start.word) % 2 != cutdown(order.word) % 2)
	{
		printf("-1");
		return 0;
	}
	Start.ca = cantor(Start.word);
	vis[1][Start.ca] = 1;
	order.ca = cantor(order.word);
	vis[0][order.ca] = 1;
	printf("%d",dbfs());
	return 0;
}
posted @ 2019-08-08 19:21  resftlmuttmotw  阅读(295)  评论(0编辑  收藏  举报