1.基础版

问题 B(1849): 【基础算法】8数码问题版本一
时间限制: 1 Sec 内存限制: 64 MB
题目描述
在一个3*3的九宫格棋盘里,放有8个数码,数码的数字分别是1~8等8个数字。可以通过在九宫格里平移数码来改变状态。数码在任何情况下都不能离开棋盘。给出8个数码的初始状态(没放数码的空格用0表示)和目标状态,问从初始状态到目标状态,最少需要经过多少次移动操作。

例如,初始状态为:

2 6 4
1 3 7
0 5 8

目标状态是:

8 1 5
7 3 6
4 0 2

最少的移动步数为31步。
输入
第1行:9个空格分开的整数,表示初始状态

第2行:9个空格分开的整数,表示目标状态

整数都在0~8范围内,且不重复

输出
第1行:1个整数,表示从初始状态到目标状态的最少移动步数。如果无解,输出-1

样例输入
2 6 4 1 3 7 0 5 8
8 1 5 7 3 6 4 0 2
样例输出
31
提示
Cantor:排列对整数的一一映射

//双向宽搜
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MAXSTA 362880
const int n=9;
int wt[n+10]={40320,5040,720,120,24,6,2,1,1};
int dir[8]={-1,1,-3,3};int spos,tpos,p[3][MAXSTA+10];
char s[n+5],t[n+5];
bool vis[3][MAXSTA+10];struct node{int step,pos,id,f;char s[n+5];node(){}node(char *str,int a,int b,int c,int e){strcpy(s,str);step=a;pos=b;id=c;f=e;};
};void read()
{int x;for(int i=0;i<n;i++){scanf("%d",&x);if(!x) spos=i;s[i]=x+'0';}for(int i=0;i<n;i++){scanf("%d",&x);if(!x) tpos=i;t[i]=x+'0';}
}
int Cantor(char *str){ //Cantor是一种排列对整数的映射,要先乘大的是因为w[]相当于每一位的进制,每一位上的数应该小于进制。int ret=0;for(int i=0;i<n;i++){for(int j=i+1;j<n;j++)if(str[j]<str[i])ret+=wt[i];}return ret;
}
int DoubleBFS()
{int num,npos;char cur[n+5];node u;queue<node> que;num=Cantor(s);que.push(node(s,0,spos,num,0));vis[0][num]=true;num=Cantor(t);que.push(node(t,0,tpos,num,1));vis[1][num]=true;while(!que.empty()){u=que.front(); que.pop();strcpy(cur,u.s);for(int i=0;i<4;i++){npos=u.pos+dir[i];if(npos>=0&&npos<n&&(u.pos%3==npos%3||u.pos/3==npos/3)){swap(cur[u.pos],cur[npos]);num=Cantor(cur);if(vis[u.f^1][num])return p[u.f^1][num]+u.step+1;else if(!vis[u.f][num]){p[u.f][num]=u.step+1;vis[u.f][num]=true;que.push(node(cur,u.step+1,npos,num,u.f));}swap(cur[u.pos],cur[npos]);}}}return -1;
}
int main()
{read();printf("%d\n",DoubleBFS());
}
//IDA*
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
#define MAXN 9
#define MAXKT 362880
struct node{char s[MAXN+10];int step,blank,f;node(){}node (char *a,int b,int c,int d){strcpy(s,a);step=b;blank=c;f=d;}bool operator<(const node& y) const{return f>y.f;}
};
int pos,w[MAXN+10];
int dir[4+5]={1,-1,3,-3};
char s[MAXN+10],t[MAXN+10];
int f[MAXKT+10],h[MAXKT+10];
void read()
{int a;for(int i=0;i<9;i++){scanf("%d",&a);s[i]=a+'0';}for(int i=0;i<9;i++){scanf("%d",&a);t[i]=a+'0';}w[8]=1;for(int i=7;i>=0;i--) w[i]=w[i+1]*(8-i);memset(f,0x3f,sizeof(f));
}
int kangtuo(char *x)
{int ret=0;for(int i=0;i<9;i++){if(x[i]=='0'){pos=i; continue;}int cnt=0;for(int j=i+1;j<9;j++)if(x[j]<x[i])cnt++;ret+=cnt*w[i];}return ret;
}
int Manhattan_Dist(char *x,char *y)
{int ret=0;for(int i=0;i<9;i++){for(int j=0;j<9;j++)if(x[i]==y[j]){ret+=(abs(j-i)/3)+(abs(j-i)%3); ///need to rethink of itbreak;}}return ret;
}
void Astar()
{priority_queue<node> que;int num=kangtuo(s);//int diff=Manhattan_Dist(s);que.push(node(s,0,pos,0));while(!que.empty()){node cur=que.top(); que.pop();char state[MAXN+10];strcpy(state,cur.s);num=kangtuo(state);if(cur.f>f[num]) continue;for(int i=0;i<4;i++){int newpos=cur.blank+dir[i];if(newpos>=0&&newpos<9&&((newpos/3==cur.blank/3)||(newpos%3==cur.blank%3))){swap(state[cur.blank],state[newpos]);if(!strcmp(state,t)){printf("%d\n",cur.step+1);return ;}int more_step=Manhattan_Dist(state,t);num=kangtuo(state);if(more_step+cur.step<f[num]){f[num]=more_step+cur.step+1;//node next; memcpy(next.s,state,sizeof state);next.step=cur.step+1,next.blank=newpos,next.f=f[num];que.push(node(state,cur.step+1,newpos,f[num]));}swap(state[cur.blank],state[newpos]);}}}printf("-1\n");return ;
}
int main()
{read();Astar();return 0;
}
2.版本二:

问题 C(1850): 【基础算法】8数码问题版本二
时间限制: 1 Sec 内存限制: 64 MB
题目描述
15数码问题已经有100多年历史了。与8数码问题类似,它由15个1~15的数码块平铺在一个4*4的棋盘上。数码的初始顺序不确定。我们希望通过平移数码块的方式得一个数码按序排序的目标状态。目标状态通常是这个样子的:(图略)

如果空格用字符’x’表示,则上图的目标状态可用以下的4行4列字符阵列表示:

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 x

如果以空格’x’作为移动对象,它可以向4个方向移动,用’r’表示右移,’l’表示左移,’u’表示上移,’d’表示下移。下面给出一个从初始状态到目标状态的移动例子:

1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12
13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x
r-> d-> r->

似乎任何一个15数码问题都应该有解的,但其实不然。In 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and frustrating many people.

下面这个图就不可解:(图略)

15数码问题的可能状态数有15!个,显然这太大了。于是在版本2中,我们仍然解决的是8数组问题。不过,这一次,我们要求输出从初始状态到固定的目标状态的移动方案。固定的目标状态是1 2 3 4 5 6 7 8 x

本题答案不唯一,所以在搜索扩展结点时,请按照上、左、下、右的顺序。

输入
第1行:9个空格分开的整数,表示8数码的初始状态,空格用小写的’x’表示。

输出
第1行:一个字符串,中间无空格,表示从初始状态到目标状态的移动方案。如果无解,输出”NO SOLUTION”

样例输入
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

2 3 4 1 5 x 7 6 8
样例输出
ullddrurdllurdruldr
提示

由于要按照顺序来找解,双向,A*都不行了,只能做最普通的BFS

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
using namespace std;
#define MAXSTA 362880
#define MAXSP 1000000
typedef long long LL;
const int n=9;
int w[20]={40320,5040,720,120,24,6,2,1,1};
int dir[10]={-3,-1,3,1};
char r[10]={'u','l','d','r'};int spos,tpos,tnum;
bool vis[MAXSTA+10];
char s[n+5],t[n+5],ans[MAXSP+10];struct node{char s[n+5];int step,pos,id;LL path;node(){}node(char *a,int b,int c,int d,LL g){strcpy(s,a);step=b;pos=c;id=d;path=g;}
};void read()
{char str[n+5];for(int i=0;i<n;i++){scanf("%s",str);if(str[0]!='x')s[i]=str[0];else{s[i]='0';spos=i;}}for(int i=0;i<n-1;i++)t[i]=i+'0'+1;t[n-1]='0';tpos=n-1;
}
int Cantor(char *str)
{int ret=0;for(int i=0;i<n;i++){for(int j=i+1;j<n;j++)if(str[j]<str[i])ret+=w[i];}return ret;
}
void print(LL x,int T)
{memset(ans,0,sizeof ans);while(T--){ans[T]=r[x%4];x/=4;}printf("%s\n",ans);
}
void BFS()
{tnum=Cantor(t);node u;queue<node> que;int num=Cantor(s),npos;char cur[n+5];que.push(node(s,0,spos,num,0));vis[num]=true;while(!que.empty()){u=que.front(); que.pop();//vis[u.id]=false;strcpy(cur,u.s);for(int i=0;i<4;i++){npos=u.pos+dir[i];if((npos>=0&&npos<9)&&(npos%3==u.pos%3||npos/3==u.pos/3)){swap(cur[npos],cur[u.pos]);num=Cantor(cur);if(!strcmp(cur,t)){//printf("%s %d\n",cur,u.step+1);print(u.path*4+i,u.step+1);return ;}if(vis[num]){swap(cur[npos],cur[u.pos]);continue;}vis[num]=true;que.push(node(cur,u.step+1,npos,num,u.path*4+i));swap(cur[npos],cur[u.pos]);}}}printf("NO SOLUTION\n");
}
bool check()
{int ta=0,tb=0;for(int i=0;i<n;i++)for(int j=i+1;j<n;j++){if(s[i]>s[j]&&s[j]!='0')ta++;if(t[i]>t[j]&&t[j]!='0')tb++;}if((ta&1)==(tb&1))return true;elsereturn false;
} //每次移动都是swap前后的两个数,如果s,t的逆序奇偶性不同是怎么都不可能成功的。
int main()
{read();if(!check()){printf("NO SOLUTION\n");return 0;}BFS();
}
3.版本三

问题 D(2627): 8数码问题版本三
时间限制: 1 Sec 内存限制: 128 MB
题目描述
在一个3*3的九宫格棋盘里,放有8个数码,数码的数字分别是1~8等8个数字。可以通过在九宫格里平移数码来改变状态。数码在任何情况下都不能离开棋盘。给出8个数码的初始状态(没放数码的空格用0表示)和目标状态,问从初始状态到目标状态,最少需要经过多少次移动操作。

例如,初始状态为:

2 6 4
1 3 7
0 5 8

目标状态是:

8 1 5
7 3 6
4 0 2

最少的移动步数为31步。
这一次,我们要解决的问题有所不同:给出初始状态,找出需要移动步数最多的状态,以及移动的方案。

输入
共3行,每行3个整数,表示初始状态

输出
前3行,每行3个整数,表示移动步数最多的目标状态

第4行:一个字符串,表示移动的方案。U表示0向上,D表示0向下,L表示0向左,R表示0向右。

样例输入
2 6 4
1 3 7
0 5 8
样例输出
8 1 5
7 3 6
4 0 2
UURDDRULLURRDLLDRRULULDDRUULDDR

题意:对于每个状态的最小步数中的最大值,还是只有暴搜(因为要搜完所有state,直接搜比较好)

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;typedef long long LL;
#define MAXSTA 362880
const int n=9;
int w[20]={40320,5040,720,120,24,6,2,1,1};
int dir[10]={-3,3,-1,1};
char r[10]={'U','D','L','R'};int dist[MAXSTA+10],spos,ans;
bool vis[MAXSTA+10];
char s[n+5],res[n+5];
LL route[MAXSTA+10];struct node{char s[n+5];int step,pos,id;LL path;node(){}node(char *a,int b,int c,int d,LL e){strcpy(s,a);step=b;pos=c;id=d;path=e;}
};
void read()
{int x;for(int i=0;i<n;i++){scanf("%d",&x);s[i]=x+'0';if(!x) spos=i;}
}
int Cantor(char *str)
{int ret=0;for(int i=0;i<n;i++)for(int j=i+1;j<n;j++)if(str[j]<str[i])ret+=w[i];return ret;
}
void BFS()
{node u;queue<node> que;int num=Cantor(s),npos;char cur[n+5];que.push(node(s,0,spos,num,0));vis[num]=true;dist[num]=0,route[num]=0;ans=MAXSTA+2;while(!que.empty()){u=que.front(); que.pop();if(dist[u.id]>=dist[ans])ans=u.id;strcpy(cur,u.s);for(int i=0;i<4;i++){npos=u.pos+dir[i];if((npos>=0&&npos<9)&&(npos%3==u.pos%3||npos/3==u.pos/3)){swap(cur[npos],cur[u.pos]);num=Cantor(cur);if(!vis[num]){vis[num]=true;dist[num]=u.step+1;route[num]=u.path*4+i;que.push(node(cur,u.step+1,npos,num,u.path*4+i));}swap(cur[npos],cur[u.pos]);}}}
}
void print(int id,LL x,int T)
{memset(vis,0,sizeof vis);for(int i=0;i<n;i++){int cnt=1;while(id>=w[i])id-=w[i],cnt++;for(int j=0;j<n;j++){if(!vis[j])cnt--;if(!cnt){printf("%d",j);vis[j]=true;break;}}if(i%3==2) printf("\n");else printf(" ");}memset(res,0,sizeof res);while(T--){res[T]=r[x%4];x/=4;}printf("%s\n",res);
}
int main()
{read();BFS();print(ans,route[ans],dist[ans]);
}

转载于:https://www.cnblogs.com/katarinayuan/p/6572841.html

8数码的各种版本-搜索相关推荐

  1. 【人工智能】八数码问题:广度搜索、深度搜索

    应用广度搜索BFS和深度搜索DFS解决八数码问题,广度搜索和深度搜索都是盲目搜索,相关理论知识,算法过程:问题求解:状态空间图和盲目搜索. 参考:7种方法求解八数码问题 Python实现A*算法解决N ...

  2. 八数码问题的广度优先搜索方法

    八数码问题的广度优先搜索方法 问题的简单描述 3×3九宫qipan,放置数码为1 -8的8个棋子,剩下一个空格,只能通过向空格的移动来改变九宫格的布局. 要求:根据给定初始布局(即初始状态)和目标布局 ...

  3. 八数码问题——双向广度优先搜索解决

    八数码问题:在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所看到的,要求对空格运行空格左移.空格右移.空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态. 搜索 ...

  4. 八数码 || 九宫重排(A*搜索代码)

    八数码 || 九宫重排 废话: 这道题如果我们用bfs确实可以跑,但是大概率会炸掉,这道题是可以双向bfs,但今天我要展示的是用A*搜索的代码 策略分析: 1,标记: 既然是搜索,那我们就肯定就要加标 ...

  5. .NET程序集版本搜索分析

    背景 多台服务器上运行多个同名程序(路径不同,配置文件不同),即某个程序有多个同名实例,运行在不同的服务器上.但由于程序为第三方提供,渐进式开发,所以每个程序的组件或者执行文件的版本,并不一样.现在需 ...

  6. jq版本搜索文本关键字高亮

    <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" ...

  7. [技术杂谈][原创]一个可以搜索老版本显卡驱动的小工具

    nvidia驱动下载都是最新十几个,如果需要很老的驱动咋办,本期就可以使用一个小工具完成老版本搜索下载任务.首先打开软件 选择自己对应驱动,可以列出很多老版本驱动点击下载即可 更多可以参考视频教程显卡 ...

  8. pip安装更新、第三方库对应的python解释器版本、pip安装第三方库,压缩包离线安装,pycharm快捷安装及pycharm中terminal的使用,timeout超时报错

    文章有点长,但是很详细,还望大家耐心看 之前在安装python的文章中已经给大家配置了pip环境变量(不了解的点这里去看看),这里就能直接在cmd窗口,不用切换路径,就能使用pip了. 首先 使用pi ...

  9. iOS xcode多版本切换

    下载Xcode 历史版本搜索 安装 目前已存在Xcode12,以安装Xcode11为例: 在 /Applications 中新建 Xcode11 文件夹. 将下载的xip文件解压,把解压后的app安装 ...

  10. Flutter搜索框SearchBar

    题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天. 重要消息 网易云[玩转大前端]配套课程 EDU配套 教程 Flutter开发的点滴积累系列文章 1 使用封装库 1.1 ...

最新文章

  1. hdu1518 bjfuoj1042 zoj1909 poj2362 经典的搜索加剪枝
  2. 关于举办第十届浙江省大学生智能汽车 竞赛暨第十六届全国大学生智能汽车竞赛 浙江赛区选拔赛的通知
  3. 农保和社保的区别有哪些
  4. linux树形目录结构存放,Linux目录结构
  5. vmware创建虚拟机不识别网卡
  6. leetcode - 461. 汉明距离
  7. 完美世界:笔试题(最小漂流船只数累计,主城之间的最小距离迪杰斯特拉)...
  8. xfire冲突问题解决(maven配置)
  9. 百度竞价教程 借助百度热力图让你的效果翻10倍
  10. 【优化求解】基于matlab粒子群算法求解干扰受限无人机辅助网络优化问题【含Matlab源码 230期】
  11. XMind中文破解版
  12. Linux基础(三)安装及管理程序
  13. layui 富文本编辑器和textarea值的相互传递
  14. OA实施周期:易用性才是关键因素
  15. c语言函数的标准写法,C语言函数的两种写法变种
  16. unity摄影机depth模式_Unity3d摄像机详解
  17. Unity ShaderGraph图片发光效果
  18. html页面tree方法,etree.html的用法问题
  19. 调用dll中的服务 提取不到数据_双枪团伙新动向,借云服务管理数十万僵尸网络...
  20. Chrome 浏览器 原生工具进行网页长截图

热门文章

  1. 如何查看 Linux 服务器性能参数指标?
  2. java 获取jboss路径_java中获取文件路径的几种方式
  3. Linux服务之批量部署篇
  4. Android之Retrofit详解(转载)
  5. Mybatis-Spring扫描路径有重叠导致Invalid bound statement(not found)问题
  6. Jmeter (三十)jmeter+ant+jenkins持续集成
  7. 漫画:女生/男生告白攻略
  8. MATLAB 动图绘制、保存
  9. 微信小程序开发基础知识总结
  10. docker容器和宿主机时间不一致的问题