zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    C++中智能指针的设计和使用
    [转]C++ 智能指针详解
    C++ const 常量和常指针
    深入理解C++中的mutable关键字
    C++ 静态常量
    BZOJ 1875: [SDOI2009]HH去散步
    BZOJ 1024: [SCOI2009]生日快乐
    BZOJ 1059: [ZJOI2007]矩阵游戏
    bzoj 1833: [ZJOI2010]count 数字计数
    LUOGU P2587 [ZJOI2008]泡泡堂
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9772910.html
Copyright © 2011-2022 走看看