八数码问题 bfs 算法入门经典

本文介绍了一种优化BFS搜索算法的方法,通过哈希表避免重复访问状态,提高了搜索效率。同时,展示了如何扩展算法以输出搜索路径,并提供了一个简单的实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码部分源自于算法入门经典,略微做了些修改。算法核心采用了bfs,但是在判断当前状态是否已经访问过时,之前试过遍历0-rear范围内bufs数组内的状态进行比较,但是太慢了,后来看了这个hash的办法,很好用。算法稍微做些添加,便可以输出一条搜索路径,这里没有给出实现。

#include <stdio.h>
#include <string.h>
#define maxn 1000000
#define maxhashsize 1000003
#define len 9*sizeof(int)

int bufs[maxn][9], goal[9], front, rear;
int head[maxhashsize], next[maxhashsize];
int d[maxn];
int fa[maxn];
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};

int hashfunc(){
	int i, sum = 0, *t = &bufs[rear][0];
	for(i = 0; i < 9; ++i) sum =sum*10 + t[i];
	return sum%maxhashsize;
}

int try_to_insert(){
	int *p, *t = &bufs[rear][0];
	int h = hashfunc();
	int u = head[h];
	while(u){
		p = &bufs[u][0];
		if(memcmp(t, p, len) == 0)  return 0;
		u = next[u];
	}
	next[rear] = head[h];
	head[h] = rear;
	return 1;
}

void init_lookup_table(){
	memset(head, 0, sizeof(head));
	int h = hashfunc();
	try_to_insert();
}

int bfs(){
	int *tmp;	
	front = 1; rear = 1;
	init_lookup_table();
	rear = 2;
	d[front] = 0;
	fa[front] = 0;
	while(front < rear){
		tmp = &bufs[front][0];
		if(memcmp(tmp, goal, len) == 0)  return front;
		int i, j, z;
		for(z = 0; z < 9; ++z) 	if(!tmp[z])   break;
		int x = z / 3, y = z % 3;
		for(i = 0; i < 4; ++i){
			int newx = x + dx[i];
			int newy = y + dy[i];
			if(newx>=0 && newy>=0 && newx<3 && newy<3)
				j = 3*newx + newy;
			else
				continue;
			int *t = &bufs[rear][0];
			memcpy(t, tmp, len);
			t[j] = tmp[z];
			t[z] = tmp[j];
			d[rear] = d[front] + 1;
			fa[rear] = front;
			if(try_to_insert()) ++rear;
		}
		++front;
	}
	return 0;
}

int main(){
	/*2 6 4 1 3 7 0 5 8      
	  8 1 5 7 3 6 4 0 2
	  d = 31*/
	int i;
	for(i = 0; i < 9; ++i)  scanf("%d", &bufs[1][i]);
	for(i = 0; i < 9; ++i)	scanf("%d", &goal[i]);
	if(bfs()) 
	 printf("%d\n", d[front]);
	else
	 printf("-1\n");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值