HDU - 3567 Eight II (bfs预处理 + 康托) [kuangbin带你飞]专题二

本文介绍了一种解决八数码问题的方法,使用C++实现,并通过广度优先搜索找到从初始状态到目标状态的最短路径。为了确保找到的路径不仅是最短的而且字典序最小,采用了特定的方向顺序进行扩展。

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

      类似HDU1430,不过本题需要枚举X的九个位置,分别保存状态,因为要保证最少步数。要保证字典序最小的话,在扩展节点时,方向顺序为:down, left, right, up.

     我用c++提交1500ms, G++提交858ms.

   AC代码

#include<cstdio>
#include<cstring>
#include<queue>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
typedef int state[9];
const int maxn = 4e5 + 5;

int vis[9][maxn];

const int dx[] = {1,0,0,-1};
const int dy[] = {0,-1,1,0};
const char dir[] = {'d','l','r','u'};

int fact[9];
void deal() {  //1~8阶乘打表,方便编码 
	fact[0] = 1;
	for(int i = 1; i < 9; ++i) fact[i] = fact[i - 1] * i;
}

int KT(int *a) {
	int code = 0;
	for(int i = 0; i < 9; ++i) {
		int cnt = 0;
		for(int j = i + 1; j < 9; ++j) if(a[j] < a[i]) cnt++;
		code += fact[8 - i] * cnt;
	}
	return code;
} 

int find_pos(int *a) {
	for(int i = 0; i < 9; ++i) {
		if(a[i] == 0) return i;
	}
}

struct node{
	int a[9];
	int code, step;
	int pos;
	node() {
	}
	node(int *b, int code, int step ,int pos):code(code), step(step), pos(pos) {
		memcpy(a, b, sizeof(a));
	}
};

struct Dirction {
	char dir;
	int step;
	int pre;
	Dirction() {
	}
	Dirction(char dir, int step, int pre):dir(dir), step(step), pre(pre){
	}
}d[9][maxn];

int st[9];

void bfs(int c) {
	queue<node>q;
	int code = KT(st);
	vis[c][code] = 1;
	d[c][code] = Dirction('x', 0, -1);
	int pp = find_pos(st);
	q.push(node(st, code, 0, pp));
	while(!q.empty()) {
		node p = q.front();
		q.pop();
		state &a = p.a;
		int pos = p.pos;
		int x = pos / 3, y = pos % 3;
		for(int i = 0; i < 4; ++i) {
			int px = x + dx[i], py = y + dy[i];
			if(px < 0 || py < 0 || px >= 3 || py >= 3) continue;
			int pz = px * 3 + py;
			swap(a[pz], a[pos]);
			code = KT(a);
			if(vis[c][code]) {
				swap(a[pz], a[pos]);
				continue;
			}
			vis[c][code] = 1;
			d[c][code] = Dirction(dir[i], p.step + 1, p.code);
			q.push(node(a, code, p.step + 1, pz));
			swap(a[pz], a[pos]);
		}
	}
}

int op[][9] = {
	0, 1, 2, 3, 4, 5, 6, 7, 8,
	1, 0, 2, 3, 4, 5, 6, 7, 8,
	1, 2, 0, 3, 4, 5, 6, 7, 8,
	1, 2, 3, 0, 4, 5, 6, 7, 8,
	1, 2, 3, 4, 0, 5, 6, 7, 8,
	1, 2, 3, 4, 5, 0, 6, 7, 8,
	1, 2, 3, 4, 5, 6, 0, 7, 8,
	1, 2, 3, 4, 5, 6, 7, 0, 8,
	1, 2, 3, 4, 5, 6, 7, 8, 0
};

void print(int code, int c) {
	if(d[c][code].pre == -1) return;
	print(d[c][code].pre, c);
	printf("%c", d[c][code].dir);
}


int main() {
	memset(vis, 0, sizeof(vis));
	deal();
	for(int i = 0; i < 9; ++i) {
		memcpy(st, op[i], sizeof(st));
		bfs(i);
	}
	int a[9], b[9];
	int T, kase = 1, ha[9];
	char s[20]; 
	scanf("%d", &T);
	while(T--) {
		int pos;
		scanf("%s", s);
		for(int i = 0; i < 9; ++i) {
			if(s[i] == 'X') {
				pos = i;
				a[i] = 0;
			}
			else a[i] = s[i] - '0';
		}
		for(int i = 0; i < 9; ++i) {
			ha[a[i]] = op[pos][i];
		}
		scanf("%s", s);
		for(int i = 0; i < 9; ++i) {
			if(s[i] == 'X') b[i] = 0;
			else b[i] = s[i] - '0';
			a[i] = ha[b[i]];
		}
		int code = KT(a);
		printf("Case %d: %d\n", kase++, d[pos][code].step);
		print(code, pos);
		printf("\n");
	}
	
	return 0;
}

如有不当之处欢迎指出!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值