HDU ACM 1043 Eight->广度优先搜索(BFS)+康托展开(全排列hash)实践

分析:经典的八数码问题,参考别人的代码写的,逆向广搜,把结果保存起来,之后在使用。

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

#define STATE_COUNT 363000  //因为9!=362880

int fact[]={1,1,2,6,24,120,720,5040,40320,362880};  //0到9的阶乘,用来计算hash值
char dir[4][2]={
	{0,1},{0,-1},{1,0},{-1,0}    //右,左,上,下
};
char dirchar[]="lrud";  //因为是从合法状态搜索出其他状态,方便之后返回时好处理,所以和搜索方向相反

class Eight_Puzzle
{
private:
	struct Node
	{
    	char map[3][3];
    	char x_pos_x,x_pos_y;

    	void GetMap(char* p);
	};

public:
	Eight_Puzzle(){}
	~Eight_Puzzle(){}
	void Bfs();              //广度搜索打表
	void OutPut(char* p);       //根据状态输出结果

private:
	void OutPut(int hash);
	int Get_Hash(Node p);     //获取某个状态的hash值

	char m_path[STATE_COUNT];
    bool m_vis[STATE_COUNT];
    int m_pre[STATE_COUNT];
	queue<Node> m_q;            //搜索队列
};

void Eight_Puzzle::OutPut(int hash)
{
	if(hash<=0) return ;

	printf("%c",m_path[hash]);
	OutPut(m_pre[hash]);
}

void Eight_Puzzle::OutPut(char* p)
{
	Node tmp;
	int hash;

	tmp.GetMap(p);
	hash=Get_Hash(tmp);

	if(!m_vis[hash])    //表中无该hash值,说明状态不可达
	{
		printf("unsolvable\n");
		return ;
	}
	else if(hash==0)    //标准状态,无需移动
	{
		printf("\n");
		return ;
	}
	else
	{
		OutPut(hash);
		printf("\n");
	}
}

void Eight_Puzzle::Bfs()
{
	char start[]="12345678x";
	Node tmp;
	int i,x,y;
	int hash0,hash;

	memset(m_path,0,sizeof(m_path));
	memset(m_vis,0,sizeof(m_vis));
	memset(m_pre,0,sizeof(m_pre));

	m_vis[0]=true;       //起点设置为拜访
	tmp.GetMap(start);
	m_q.push(tmp);        //起始状态入队

	while(!m_q.empty())
	{
		tmp=m_q.front();
		hash0=Get_Hash(tmp);       //队头的hash,当前步
		for(i=0;i<4;i++)
		{
			tmp=m_q.front();       //每次都重新取出队头

			x=tmp.x_pos_x+dir[i][0];
			y=tmp.x_pos_y+dir[i][1];
			if(x<0 || y<0 || x>=3 || y>=3)
				continue;

			swap(tmp.map[tmp.x_pos_x][tmp.x_pos_y],tmp.map[x][y]);
			tmp.x_pos_x=x;               //更新坐标
			tmp.x_pos_y=y;
	     	hash=Get_Hash(tmp);
			if(m_vis[hash])
				continue;

			m_vis[hash]=true;
			m_pre[hash]=hash0;
			m_path[hash]=dirchar[i];
			m_q.push(tmp);
		}
		m_q.pop();           //队头出队,状态已处理
	}
}

int Eight_Puzzle::Get_Hash(Node p)
{
	char s[10];
	int i,j,k,count;
	int hash=0;

	for(i=0;i<3;i++)
		for(j=0;j<3;j++)
		{
			count=0;
			s[i*3+j]=p.map[i][j];
			for(k=i*3+j-1;k>=0;k--)
				if(s[k]>s[i*3+j])
					count++;
			hash+=count*fact[i*3+j];
		}
	return hash;
}

void Eight_Puzzle::Node::GetMap(char* p)
{
	int i,j;

	i=j=0;
    while(*p)
	{
	   	if(*p>='1' && *p<='8' || *p=='x')
		{
     		map[i][j]=*p;
	   		if(map[i][j]=='x')
			{
				map[i][j]='9';
				x_pos_x=i;
				x_pos_y=j;
			}
			j++;
			if(j>=3)
			{
				i++;
				j=0;
			}
		}
		p++;
	}
}

int main()
{
	char a[50];
	Eight_Puzzle* eight_puzzle=(Eight_Puzzle*)new Eight_Puzzle;

	eight_puzzle->Bfs();          //打表,保存所有合法移动的步骤
	while(gets(a))
	{
		eight_puzzle->OutPut(a);
	}
	delete eight_puzzle;
    return 0;
}
时间: 2024-08-01 10:45:44

HDU ACM 1043 Eight->广度优先搜索(BFS)+康托展开(全排列hash)实践的相关文章

HDU 1043 Eight(双向BFS+康托展开)

http://acm.hdu.edu.cn/showproblem.php?pid=1043 题意:给出一个八数码,求出到达指定状态的路径. 思路:路径寻找问题.在这道题里用到的知识点挺多的.第一次用双向BFS来做. ①双向BFS 在单向BFS的基础上,多建一个从终止状态开始搜索的队列,当然这个时候需要两个vis[]辅助数组,分别记录两个队列的访问情况,当两个队列相遇时即可终止循环. ②康托展开 X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[

poj 1077 八数码(BFS+康托展开)

1 /* 2 题意:八数码问题,给出3*3的矩阵含1~8以及x,给出一个符合的解使得移动后的矩阵的顺序为1~8,最后为x 3 4 题解:BFS 5 需要用到康托展开来表示状态,不然数组无法完全表示所有状态,这样BFS就无法判断找不到解的情况(status 6 的0ms,0KB究竟是怎么做到的,简直不能想象=.=) 7 */ 8 #include <cstdio> 9 #include <cstring> 10 #include <queue> 11 #include &

【HDU - 1043】Eight(反向bfs+康托展开)

Eight Descriptions: 简单介绍一下八数码问题:在一个3×3的九宫格上,填有1~8八个数字,空余一个位置,例如下图: 1 2 3 4 5 6 7 8   在上图中,由于右下角位置是空的,你可以移动数字,比如可以将数字6下移一位: 1 2 3   1 2 3 4 5 6 → 4 5   7 8     7 8 6 或者将数字8右移一位: 1 2 3   1 2 3 4 5 6 → 4 5 6 7 8     7   8 1~8按顺序排列的情况称为"初始状态"(如最上方图)

hdu 1430 (BFS 康托展开 或 map )

第一眼看到这题就直接BFS爆搜,第一发爆了内存,傻逼了忘标记了,然后就改,咋标记呢. 然后想到用map函数,就8!个不同的排列,换成字符串用map标记.然后又交一发果断超时,伤心,最恨超时,还不如来个wa算了. 然后卡着了,后来上网上搜了,要用康托展开,康托展开是什么鬼?然后学习了一下,就是个映射,感觉和map差不多. http://blog.csdn.net/zhongkeli/article/details/6966805这个学习一下康托展开. 其实本题的关键不是康托展开,而是置换. 以12

广度优先搜索(BFS)

广度优先 Description: 阿狸被困在迷宫,snoopy要去救他,snoopy可以向上.下.左.右四个方向行走,每走一步(格)就要喝掉一瓶益力多.现在给它一个迷宫地图请问:snoopy最少需要多少瓶益力多才能走出迷宫? Input: 先输入一个数t,表示测试的数据个数, 下面输入的就是t个迷宫, 每个迷宫的输入都应包含以下数据, 输入迷宫的大小 n(n<=15),表示迷宫大小为n*n. 再输入迷宫, 用大写字母“S”表示snoopy的位置, 用小写字母“E”表示阿狸被困的位置, 用“.”

【算法导论】--C++实现广度优先搜索bfs

一.题目 根据上次随机生成的100个顶点的无向图和有向图,对其进行广度优先搜索. 二.理解广度优先搜索 广度优先搜索可以将其想象成水滴落入水面溅起了的一圈一圈的涟漪,是由一个起始点开始一圈一圈进行扩散搜索的. [课上老师是这样说的,大家想象一下,发现其实非常形象] 广度优先搜索总是从一个起始点出发,首先扩散这个点周围所有的邻居,然后邻居在去扩散邻居的邻居(*^-^*)...然后一直到最后将整张图都扩散完. 三.代码实现 对于第一次随机生成100个顶点的图进行了细节的修改,将每个顶点的类型改为了自

hdu 5012 bfs 康托展开

Dice Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 491    Accepted Submission(s): 290 Problem Description There are 2 special dices on the table. On each face of the dice, a distinct number w

深度优先搜索DFS和广度优先搜索BFS

DFS简介 深度优先搜索,从起点开始按照某个原则一直往深处走,直到找到解,或者走不下去,走不下去则回溯到前一节点选择另一条路径走,直到找到解为止. BFS简介 广度优先搜索,从起点开始先搜索其相邻的节点,由此向外不断扩散,直到找到解为止. 举例解释 从1开始去寻找5 DFS: 原则:优先选择左手边 过程:1-2-3-4-6-4-5 BFS: 队列情况:1 2.5     5.3 5出来则找到 遍历图中所有点 DFS: 原则:优先选择左手边 过程:1-2-3-4-6-4-5 BFS: 队列情况:1

算法与数据结构基础 - 广度优先搜索(BFS)

BFS基础 广度优先搜索(Breadth First Search)用于按离始节点距离.由近到远渐次访问图的节点,可视化BFS 通常使用队列(queue)结构模拟BFS过程,关于queue见:算法与数据结构基础 - 队列(Queue) 最直观的BFS应用是图和树的遍历,其中图常用邻接表或矩阵表示,例如 LeetCode题目 690. Employee Importance: // LeetCode 690. Employee Importance/* class Employee { publi

广度优先搜索BFS

广度优先搜索可以形成一个广度优先搜索树 算法时间为O(V+E),两重循环 输入:图g,起点start(int) 需要的数据结构:队列Q.color数组(存放每个顶点的颜色) 算法过程: 1. 预处理:1)color数组的每个值都赋为white(表示没被访问过):2)队列Q为空队列 2. 处理起点: 1)color[start]=gray,gray表示顶点已被访问,但其子节点未被处理(指的是入队列):2)Q.enQueue(start) 3. 循环以下操作,直到Q为空 1)int u=Q.deQu