Luogu2578 [ZJOI2005]九数码游戏

Posted xcysblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu2578 [ZJOI2005]九数码游戏相关的知识,希望对你有一定的参考价值。

状态数不是很多,直接 bfs

输出方案就记录 pre 状态即可

 

但是问题在于存状态

可行的一些方案是:哈希/map,康托展开

于是就学了一波康托展开

 

用康托展开的地方的地方感觉不会很多,毕竟要 n^2 算

大概意思就是给一个排列 hash

计算出来的就是这个排列在所有 n 的排列中的排名

计算方式就从这里看吧

不过代码实现略有不同

大体思路是差不多的

逆展开就是当前这一位上的数字的排名

从可用数字中选出这个排名的数,并把它从可用集合中删除


 代码:

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cstdio>
#include<queue>
using namespace std;

const int MAXN = 11, MAXSIZ = 5;

struct INFO{
	int stt[MAXN], stp, ex;
}bgn;
int ans, top;
int pi[MAXN], out[MAXN], tmp[MAXN];
int stp[363000], pre[363000], stk[363000];
bool getans, vis[10];
queue<INFO> q;

inline void turnmid(int *stt) {
	register int tmp = stt[4];
	stt[4] = stt[6]; stt[6] = stt[5]; stt[5] = tmp;
	return;
}
inline void turnroll(int *stt) {
	register int tmp = stt[1];
	stt[1] = stt[4]; stt[4] = stt[7]; stt[7] = stt[8];
	stt[8] = stt[9]; stt[9] = stt[6]; stt[6] = stt[3];
	stt[3] = stt[2]; stt[2] = tmp;
	return;
}
inline int expnd(int *dst) {
	register int res = 0, tmp = 0;
	for(int i = 1; i <= 9; ++i) {
		tmp = 0;
		for(int j = i + 1; j <= 9; ++j) tmp += (dst[j] < dst[i]);
		res += tmp * pi[9 - i];
	}
	return res;
}
inline void antiex(int ex) {
	register int siz = 8, val = 0;
	for(int i = 0; i < 9; ++i) tmp[i] = i;
	for(int i = 1; i <= 9; ++i) {
		val = (ex / pi[9 - i]);
		ex %= pi[9 - i];
		out[i] = tmp[val];
		for(int j = val; j < siz; ++j) tmp[j] = tmp[j + 1];
		--siz; 
	}
	return;
}
inline void write(int ex) {
	getans = true;
	while(~ex) {
		stk[++top] = ex;
		//printf("ex = %d
", ex);
		ex = pre[ex];
	}
	while(top) {
		antiex(stk[top--]);
		for(int i = 1; i <= 9; ++i) 
			printf("%d%c", out[i], " 
"[i % 3 == 0]);
		putchar(‘
‘);
	}
	return;
}
inline void bfs() {
	bgn.ex = expnd(bgn.stt);
	bgn.stp = 0;
	pre[bgn.ex] = -1;
	stp[bgn.ex] = 0;
	q.push(bgn);
	INFO cur, d1, d2;
	while(!q.empty()) {
		cur = q.front(); q.pop();
		//printf("now state : 
");
		//for(int i = 1; i <= 9; ++i) 
		//	printf("%d%c", cur.stt[i], " 
"[i % 3 == 0]);
		++cur.stp;
		d1 = cur;
		d2 = cur;
		turnroll(d1.stt);
		turnmid(d2.stt);
		d1.ex = expnd(d1.stt);
		d2.ex = expnd(d2.stt);
		if(stp[d1.ex] > d1.stp) {
			stp[d1.ex] = d1.stp;
			pre[d1.ex] = cur.ex;
			q.push(d1);
		}
		if(stp[d2.ex] > d2.stp) {
			stp[d2.ex] = d2.stp;
			pre[d2.ex] = cur.ex;
			q.push(d2);
		}
		if(d1.ex == ans) {
			printf("%d
", d1.stp);
			write(d1.ex);
			return;
		}
		if(d2.ex == ans) {
			printf("%d
", d2.stp);
			write(d2.ex);
			return;
		}
	}
	return;
}

int main() {
	memset(stp, 0x3f, sizeof(stp));
	pi[0] = pi[1] = 1;
	for(int i = 0 ;i < 363000; ++i) pre[i] = -1;
	for(int i = 2; i <= 9; ++i) 
		pi[i] = pi[i - 1] * i;
	for(int i = 1; i <= 9; ++i) bgn.stt[i] = i - 1;
	ans = expnd(bgn.stt);
	for(int i = 1; i <= 9; ++i) 
		scanf("%d", &bgn.stt[i]);
	bfs();
	if(!getans) 
		puts("UNSOLVABLE");
	return 0;
}

以上是关于Luogu2578 [ZJOI2005]九数码游戏的主要内容,如果未能解决你的问题,请参考以下文章

luogu1169 [ZJOI2007]棋盘制作

Luogu P2577 [ZJOI2005]午餐(dp)

luogu2577 [ZJOI2005] 午餐 贪心

[luogu2579 ZJOI2005] 沼泽鳄鱼(矩阵快速幂)

「 Luogu P1379 」 八数码难题

ZJOI2005午餐