http://acm.hdu.edu.cn/showproblem.php?pid=3567

相比Eight,似乎只是把目标状态由确定的改成不确定的,但是康托展开+曼哈顿为h值的A*和IDA*都不过,而且也不好控制字典序

换个角度想,虽然起始状态有很多,但是到底哪一位是1,哪一位是2不是最重要的,最重要的是和目标状态对应,所以可以把起始状态重新编码为"12345678"这种形式(先不考虑X),然后目标状态也对应过去,当考虑X的时候,我们可以认为起始状态只有9种,分别是'X'在各个位置的情况

利用bfs可以得到每种起始状态到对应的能够达到的所有目标状态的最短最小字典序转移方法,如果对每个状态都记录一个字符串肯定会MLE,所以只需要记录上一个状态到这一个状态转移所需要的操作即可

最后,对于每个目标状态,逆向推出状态转移序列,然后逆着输出即可

ps:一次处理3.6e6个状态,如果不用queue或者循环数组会MLE,如果不用g++提交而用c++提交会TLE

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cctype>
using namespace std;
const int base[9]={1,1,2,6,24,120,720,5040,40320};
const int dx[4]={1,0,0,-1};/转移方向,遵从字典序最小
const int dy[4]={0,-1,1,0};
const int maxh=362880;//每种开始状态所对应状态数
int des;//用于存储目标状态hash值,判断是否不需要转移
struct pnt{
int maz[3][3];
int ind;//标记起始状态的编号
int x,y;
int hashCode;
pnt(){
x=y=hashCode=-1;
}
pnt(char * str){
for(int i=0;i<9;i++){
if(str[i]=='X'){
maz[i/3][i%3]=9;
x=i/3;
y=i%3;
ind=i;
}
else maz[i/3][i%3]=str[i]-'0';
}
}
int gethashcode(){
int ans=0;
for(int i=0;i<9;i++){
int cnt=0;
for(int j=0;j<i;j++){
if(maz[j/3][j%3]>maz[i/3][i%3]){
cnt++;
}
}
ans+=base[i]*cnt;
}
return hashCode=ind*maxh+ans;
}
};
bool in(int tx,int ty){
return tx>=0&&tx<3&&ty>=0&&ty<3;
} int vis[maxh*10+1];//用于存储某状态是否已被遍历,并存储由何种操作得到该状态
int pre[maxh*10+1];//用于存储某状态由何种状态转移得到
queue<pnt> que;
char ans[maxh*10+1];//存储答案的逆序
char buff[300];//存储输入
pnt s,e;
int ind[10],indlen;//用于重新编码
bool input(){
if(scanf("%s",buff)!=1)return false;
indlen=0;//重新编码
for(int i=0;i<9;i++){
if(buff[i]>='0'&&buff[i]<='9'){
s.maz[i/3][i%3]=++indlen;
ind[buff[i]-'0']=indlen;
}
else{
s.maz[i/3][i%3]=9;
s.x=i/3;
s.y=i%3;
s.ind=i;
}
}
if(scanf("%s",buff)!=1)return false;
for(int i=0;i<9;i++){
if(buff[i]>='0'&&buff[i]<='9'){
e.maz[i/3][i%3]=ind[buff[i]-'0'];
}
else{
e.maz[i/3][i%3]=9;
e.x=i/3;
e.y=i%3;
}
}
e.ind=s.ind;//起始状态相同
des=e.gethashcode();
return true;
}
void bfs(){
while(!que.empty()){
pnt tp=que.front();que.pop();
int x=tp.x,y=tp.y;
for(int i=0;i<4;i++){
int tx=x+dx[i],ty=y+dy[i];
if(in(tx,ty)){
pnt nw=tp;
swap(nw.maz[tx][ty],nw.maz[x][y]);
nw.x=tx,nw.y=ty;
if(vis[nw.gethashcode()]==-1){
vis[nw.hashCode]=i;
pre[nw.hashCode]=tp.gethashcode();
que.push(nw);
}
}
}
}
}
void init(){
memset(vis,-1,sizeof(vis));
memset(pre,-1,sizeof(pre));
pnt s1=pnt("12345678X");//9种起始状态加入序列
vis[s1.gethashcode()]=-2;
que.push(s1);
pnt s2=pnt("1234567X8");
vis[s2.gethashcode()]=-2;
que.push(s2);
pnt s3=pnt("123456X78");
vis[s3.gethashcode()]=-2;
que.push(s3);
pnt s4=pnt("12345X678");
vis[s4.gethashcode()]=-2;
que.push(s4);
pnt s5=pnt("1234X5678");
vis[s5.gethashcode()]=-2;
que.push(s5);
pnt s6=pnt("123X45678");
vis[s6.gethashcode()]=-2;
que.push(s6);
pnt s7=pnt("12X345678");
vis[s7.gethashcode()]=-2;
que.push(s7);
pnt s8=pnt("1X2345678");
vis[s8.gethashcode()]=-2;
que.push(s8);
pnt s9=pnt("X12345678");
vis[s9.gethashcode()]=-2;
que.push(s9);
bfs();
}
int heap[maxh],sz;
int getans(pnt e){//逆序遍历
sz=0;
int last=e.gethashcode();
while(pre[last]>=0){
heap[sz++]=vis[last];
last=pre[last];
}
return sz;
}
void print(){
for(int i=sz-1;i>=0;i--){
switch(heap[i]){
case 0:
putchar('d');break;
case 1:
putchar('l');break;
case 2:
putchar('r');break;
case 3:
putchar('u');break;
}
}
putchar('\n');
}
int main(){
int T;
scanf("%d",&T);
init();
for(int ti=1;ti<=T;ti++){
input();
s.hashCode=s.gethashcode();
if(s.hashCode==des){
printf("Case %d: 0\n",ti);
puts("");
continue;
}
vis[s.hashCode]=-2;
int step=getans(e);
printf("Case %d: %d\n",ti,step);
print();
}
return 0;
}

  

HDU 3567 Eight II 打表,康托展开,bfs,g++提交可过c++不可过 难度:3的更多相关文章

  1. HDU 1043 & POJ 1077 Eight(康托展开+BFS+预处理)

    Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30176   Accepted: 13119   Special ...

  2. HDU 1043 & POJ 1077 Eight(康托展开+BFS | IDA*)

    Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30176   Accepted: 13119   Special ...

  3. HDU 3567 Eight II(八数码 II)

    HDU 3567 Eight II(八数码 II) /65536 K (Java/Others)   Problem Description - 题目描述 Eight-puzzle, which is ...

  4. HDU 1043 Eight(反向BFS+打表+康托展开)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 题目大意:传统八数码问题 解题思路:就是从“12345678x”这个终点状态开始反向BFS,将各 ...

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

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

  6. [HDOJ1043]Eight(康托展开 BFS 打表)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 八数码问题,因为固定了位置所以以目标位置开始搜索,把所有情况(相当于一个排列)都记录下来,用康托 ...

  7. hdu-1043(八数码+bfs打表+康托展开)

    参考文章:https://www.cnblogs.com/Inkblots/p/4846948.html 康托展开:https://blog.csdn.net/wbin233/article/deta ...

  8. HDU1430 BFS + 打表 + 康托展开

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1430 , 一道比较好的题. 这道题要用到很多知识,康托展开.BFS.打表的预处理还要用到一一映射,做完 ...

  9. HDU 1430 魔板(康托展开+BFS+预处理)

    魔板 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submis ...

随机推荐

  1. [转]Java代码(性能)优化总结

    前言 代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用, ...

  2. Memcache的安装

    下载安装包: wget http://www.memcached.org/files/memcached-1.4.32.tar.gz wget https://cloud.github.com/dow ...

  3. (二)再议MII、RMII、GMII接口

    概述:         MII (Media Independent Interface(介质无关接口)或称为媒体独立接口,它是IEEE-802.3定义的以太网行业标准.它包括一个数据接口和一个MAC ...

  4. Android控件_TextView(显示文本框控件)

    一.TextView控件的常用属性  1.android:id——控件的id   2.android:layout_width——设置控件的宽度 wrap_content(包裹实际文本内容) fill ...

  5. Python 调用自定义包

    创建包 # mkdir -p /python/utils # touch /python/utils/__init__.py # vi /python/utils/Log.pyimport timed ...

  6. 选择排序算法Java与Python实现

    Java 实现 package common; public class SimpleArithmetic { /** * 选择排序 * 输入整形数组:a[n] [4.5.3.7] * 1. 取数组编 ...

  7. 项目中的五级地址联动效果(js)

    我刚开始是的时候是是写了一个sql语句,但是写了5个函数,来联动地址的.后来请教了前段的师傅,用js来写了一个地址联动的. 我使用的是easyui的框架! 地址联动部分html代码! <tr&g ...

  8. Gitweb 安装与配置

    gitweb 可以通过搭建git服务器将代码保存在git服务器上,多个开发者可以从服务器上clone代码,也可以各自维护一份本地代码,在本地更新之后可以提交到git服务器上,提高开发效率.     g ...

  9. SVN使用汇总

    SVN项目管理文件夹:Tag/Branch/Trunk Trunk:在我经历的开发中,新建Trunk意味着对旧Trunk的一个保留,同时在新的Trunk中可以进行新功能的开发及对已有功能进行完善: B ...

  10. idea+git

    http://www.cnblogs.com/java-maowei/p/5950930.html