算法竞赛入门经典:第七章 暴力求解法 7.18八数码问题之哈希去重

/*
八数码问题之哈希去重:
输入:
2 6 4 1 3 7 0 5 8
8 1 5 7 3 6 4 0 2
输出:
31
*/

/*
关键:
1 哈希:把结点变成整数,但不必是一一对应。设计一个哈希函数h(x),然后将任意结点x映射到某个给定的范围[0,M-1]的整数即可,其中M是程序员根据可用内存大小
自选的。不同结点哈希值相同时,用链表组织哈希值相同的链表。
2 iSum = 10 * iSum + s[i];//把9个数字组成九位数,妙哉
3 return iSum % MAXHASHSIZE;//确保hash函数值不超过hash表的大小的非负整数这里除数尽量取大质数
4 	int h = hash(st[x]);//求第x个状态组对应的哈希值
	int u = iHead[h];//向获取每条链中的链首值
	while(u)//这个while的作用是遍历具有相同哈希值的一条链,如果能找到,说明插入失败,如果找不到,则采用头插法插入新来的节点
	{
		if(memcmp(st[u],st[x],sizeof(st[x])) == 0)//如果发现经过哈希值计算中的某个结点与源节点相同,说明之前已经有过该状态值,此时该状态相当于已访问
		{
			return false;
		}
		u = iNext[u];
	}
	iNext[x] = iHead[h];//采用头插法,获取头结点的指向
	iHead[h] = x;//将链中加入第x个状态编号
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

const int MAXSIZE = 1000000;
typedef int State[9];
State st[MAXSIZE],stEnd;
const int MAXHASHSIZE = 100003;
int iHead[MAXHASHSIZE];
int iNext[MAXSIZE];
int iDist[MAXSIZE];
int go[][2] = 
{
	{-1,0},
	{1,0},
	{0,-1},
	{0,1}
};

int hash(State& s)
{
	int iSum = 0;
	for(int i = 0 ; i < 9 ; i++)
	{
		iSum = 10 * iSum + s[i];//把9个数字组成九位数,妙哉
	}
	return iSum % MAXHASHSIZE;//确保hash函数值不超过hash表的大小的非负整数这里除数尽量取大质数
}

bool isInsert(int x)
{
	int h = hash(st[x]);//求第x个状态组对应的哈希值
	int u = iHead[h];//向获取每条链中的链首值
	while(u)//这个while的作用是遍历具有相同哈希值的一条链,如果能找到,说明插入失败,如果找不到,则采用头插法插入新来的节点
	{
		if(memcmp(st[u],st[x],sizeof(st[x])) == 0)//如果发现经过哈希值计算中的某个结点与源节点相同,说明之前已经有过该状态值,此时该状态相当于已访问
		{
			return false;
		}
		u = iNext[u];
	}
	iNext[x] = iHead[h];//采用头插法,获取头结点的指向
	iHead[h] = x;//将链中加入第x个状态编号
	return true;
}


int bfs()
{
	int iFront = 1,iRear = 2;
	memset(iHead,0,sizeof(iHead));
	while(iFront < iRear)
	{
		State& state = st[iFront];
		if(memcmp(stEnd,state,sizeof(state)) == 0)
		{
			return iFront;
		}
		int iX,iY,iZ;
		for(iZ = 0 ; iZ < 9 ; iZ++)
		{
			if(!state[iZ])
			{
				break;
			}
		}
		iX = iZ / 3;
		iY = iZ % 3;
		int iNewZ,iNewX,iNewY;
		for(int i = 0 ; i < 4; i++)
		{
			iNewX = go[i][0] + iX;
			iNewY = go[i][1] + iY;
			iNewZ = iNewX * 3 + iNewY;
			if(iNewX >= 0 && iNewX < 3 && iNewY >= 0 && iNewY < 3)
			{
				State& newState = st[iRear];
				memcpy(&newState,&state,sizeof(state));
				newState[iNewZ] = state[iZ];
				newState[iZ] = state[iNewZ];
				iDist[iRear] = iDist[iFront] + 1;
				if(isInsert(iRear))
				{
					iRear++;
				}
			}
		}
		iFront++;
	}
	return -1;
}

void process()
{
	iDist[1] = 0;
	for(int i = 0; i < 9; i++)
	{
		scanf("%d",&st[1][i]);
	}
	for(int j = 0 ; j < 9 ; j++)
	{
		scanf("%d",&stEnd[j]);
	}
	int iRes = bfs();
	if(iRes > 0)
	{
		printf("%d\n",iDist[iRes]);
	}
	else
	{
		printf("-1\n");
	}
}

int main(int argc,char* argv[])
{
	process();
	system("pause");
	return 0;
}

你可能感兴趣的:(算法竞赛)