[ZJOI2005]九数码游戏(BFS+hash)

Solution
这题的话直接上BFS就可以了,因为要输出方案,所以我们要开一个pre数组记录前驱,最后输出就可以了。
对于状态的记录,一般都用哈希来存,但因为这道题比较特殊,它是一个排列,所以我们可以利用康拓展开把空间压到9!。
康拓展开
一个排列的康拓展开表示的是字典序比他小的排列的个数,所以我们统计一下每一位后面有几个比它小的数字,乘上(n-i)!
inline int zx_hash(int x){
for(int i=;i>=;--i)a[i]=x%,x/=;
int num=;
for(int i=;i<=;++i){
int aa=;
for(int j=i+;j<=;++j)if(a[i]>a[j])aa++;
num+=aa*jie[-i];
}
return num;
}
逆康拓展开
我们不但要支持把排列映射成数字,还要支持把数字映射成排列。
具体操作就是从高到低按位考虑,令x=num/(n-i)!,那么可选集合中有x个数是比这一位上的数字小的,所以我们选择第x+1个数。
inline int anti_hash(int x){
int num=;
for(int i=;i<=;++i)vec[i]=i;int zo=;
for(int i=;i>=;--i){
int y=x/jie[i];
x=x%jie[i];
num=num*+vec[y];
for(int j=y;j<zo;++j)vec[j]=vec[j+];zo--;
}
return num;
}
不过康拓展开的复杂度是n^2的,但常数较小,遇到哈希排列之类的问题试一下。
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<algorithm>
#define mm make_pair
#define N 12
using namespace std;
const int r1[]={,,,,,,,,,};
const int r2[]={,,,,,,,,,};
int jie[N],a[N],d1[N],d2[N],x,win,ans[],ji[],tag,tot,vec[];
struct node{
int first,second;
};
queue<node>q;
inline int zx_hash(int x){
for(int i=;i>=;--i)a[i]=x%,x/=;
int num=;
for(int i=;i<=;++i){
int aa=;
for(int j=i+;j<=;++j)if(a[i]>a[j])aa++;
num+=aa*jie[-i];
}
return num;
}
inline int anti_hash(int x){
int num=;
for(int i=;i<=;++i)vec[i]=i;int zo=;
for(int i=;i>=;--i){
int y=x/jie[i];
x=x%jie[i];
num=num*+vec[y];
for(int j=y;j<zo;++j)vec[j]=vec[j+];zo--;
}
return num;
}
int main(){
for(int i=;i<=;++i)scanf("%d",&a[i]),x=x*+a[i];jie[]=;int mem=x;
for(int i=;i<=;++i)jie[i]=jie[i-]*i;
win=zx_hash();
q.push(node{zx_hash(x),});
while(!q.empty()){
int u=q.front().first,nn=q.front().second;q.pop();
if(u==win){
printf("%d\n",nn);
tag=;
break;
}
x=anti_hash(u);
for(int i=;i>=;--i)d1[r1[i]]=x%,d2[r2[i]]=x%,x/=;
int x1=,x2=;
for(int i=;i<=;++i)x1=x1*+d1[i],x2=x2*+d2[i];
x1=zx_hash(x1);x2=zx_hash(x2);
if(!ji[x1])ji[x1]=u,q.push(node{x1,nn+});
if(!ji[x2])ji[x2]=u,q.push(node{x2,nn+});
}
if(!tag){
printf("UNSOLVABLE");
return ;
}
x=mem;x=zx_hash(x);
while(win!=x){
ans[++tot]=win;win=ji[win];
}
ans[++tot]=x;
for(int i=tot;i>=;--i){
int qq=anti_hash(ans[i]);
for(int j=;j>=;--j)a[j]=qq%,qq/=;
printf("%d %d %d\n%d %d %d\n%d %d %d\n\n",a[],a[],a[],a[],a[],a[],a[],a[],a[]);
}
return ;
}
[ZJOI2005]九数码游戏(BFS+hash)的更多相关文章
- [ZJOI2005]九数码游戏
[ZJOI2005]九数码游戏 题目描述 输入输出格式 输入格式: 输入文件中包含三行三列九个数,同行的相邻两数用空格隔开,表示初始状态每个方格上的数字.初始状态不会是目标状态. 输出格式: 如果目标 ...
- 洛谷 P2578 [ZJOI2005]九数码游戏【bfs+康托展开】
只有9!=362880个状态,用康托展开hash一下直接bfs即可 #include<iostream> #include<cstdio> #include<cstrin ...
- LG2578 「ZJOI2005」九数码游戏 bfs
问题描述 LG2578 题解 用string+map去重. bfs即可. \(\mathrm{Code}\) #include<bits/stdc++.h> using namespace ...
- 洛谷 - P2578 - 九数码游戏 - bfs
https://www.luogu.org/problemnew/show/P2578 一个挺搞的东西,用康托展开做记忆化搜索可以少一个log的查询. #include <bits/stdc++ ...
- 万圣节后的早晨&&九数码游戏——双向广搜
https://www.luogu.org/problemnew/show/P1778 https://www.luogu.org/problemnew/show/P2578 双向广搜. 有固定起点终 ...
- HDU-1043 Eight八数码 搜索问题(bfs+hash 打表 IDA* 等)
题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原 ...
- 【BZOJ】1054: [HAOI2008]移动玩具(bfs+hash)
http://www.lydsy.com/JudgeOnline/problem.php?id=1054 一开始我还以为要双向广搜....但是很水的数据,不需要了. 直接bfs+hash判重即可. # ...
- C#_界面程序_数码游戏
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- [BZOJ1054][HAOI2008]移动玩具 bfs+hash
1054: [HAOI2008]移动玩具 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2432 Solved: 1355[Submit][Stat ...
随机推荐
- Kernel Functions-Introduction to SVM Kernel & Examples - DataFlair
Kernel Functions-Introduction to SVM Kernel & Examples - DataFlairhttps://data-flair.training/bl ...
- 【Python3练习题 016】 猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少。
这题得倒着推.第10天还没吃,就剩1个,说明第9天吃完一半再吃1个还剩1个,假设第9天还没吃之前有桃子p个,可得:p * 1/2 - 1 = 1,可得 p = 4.以此类推,即可手算出. 代码思路为: ...
- node错误中间件处理 express类 带有路由操作
let express = require('express'); let app = new express(); let bodyParser = require('body-parser'); ...
- 安装splash
参考: https://blog.csdn.net/qq_41020281/article/details/82599075
- 神经网络-SGD-2
接上节: 3.梯度(gradient): def numerical_gradient(f,x): h=1e-5 grad=np.zeros_like(x) for index_x in range( ...
- 在阿里云上部署 Postfix
Postfix 可以很方便的在一台机器上部署 smtp 服务,在 centos 上来说的话可以使用: sudo yum install postfix sudo systemctl enable po ...
- 《笔记》Apache2 mod_wsgi的配置
接手了一台古老的服务器的还使用的是mod_wsgi,所以需要配置一下.其实这里有点怀念,记得当年自己折腾第一个app的时候,还是个什么都不懂的菜鸡.当时用django搜方案的时候,还不知道有uwsgi ...
- flask 下载本地文件
下载本地文件就是找到文件路径 调用flask自带的send_file(路径)下载, 并返回 flask: # 下载文件 from flask import send_file@task_mgm.ro ...
- vscode git设置
vscode只能打开一下界面: 在setting.path增加git.path选项,再使用linux的方法配置路径,就是使用D:/../bin/git.exe而不是\\ 重启vscode,git设置即 ...
- 三、Docker网络
一.查看8001端口是否开启处监听状态 netstat -apnl | grep 8001 二.使用brctl show可以看到虚拟机的网络关系 brctl show docker每新建一个conta ...