八数码难题 洛谷1379
来源:互联网 发布:淘宝联盟认证 编辑:程序博客网 时间:2024/06/05 02:06
洛谷1379八数码难题 单向宽搜+map判重 1584ms / 26.76MB双向宽搜+康托展开 18ms / 24.29MB
题目描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入输出格式
输入格式:
输入初试状态,一行九个数字,空格用0表示
输出格式:
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
输入输出样例
输入样例#1:
283104765
输出样例#1:
4
#include<iostream>#include<cstdio>#include<cstring>#include<map>#include<queue>using namespace std;string st,aim=" 123804765",s,si;char x;map<string,int>p;queue<string>q;queue<int>t;int main(){ cin>>st; st=' '+st; q.push(st); p[st]=1; t.push(0); while(!q.empty()) { s=q.front(); int step=t.front(); t.pop();q.pop(); if(s==aim) { cout<<step<<endl; return 0; } si=s; int pi=si.find("0"); if(pi+3<=9) { x=si[pi+3];si[pi+3]=si[pi];si[pi]=x; if(p[si]==0) { q.push(si);t.push(step+1); p[si]=1; } } si=s; if(pi-3>=1) { x=si[pi-3];si[pi-3]=si[pi];si[pi]=x; if(p[si]==0) { q.push(si);t.push(step+1); p[si]=1; } } si=s; if(pi+1<=9&&pi!=3&&pi!=6) { x=si[pi+1];si[pi+1]=si[pi];si[pi]=x; if(p[si]==0) { q.push(si);t.push(step+1); p[si]=1; } } si=s; if(pi-1>=1&&pi!=7&&pi!=4) { x=si[pi-1];si[pi-1]=si[pi];si[pi]=x; if(p[si]==0) { q.push(si);t.push(step+1); p[si]=1; } } }}
/*八个数码可能构成的状态共有9!=362880种情况,可以用宽搜的方法,每种状态用一个九位的int来存储,并确保无重复,需要开bool数组来对各种状态进行标记。于是10^8这样大的数组是空间复杂度难以接受。而如果将八数码的所有状态合看作是一个全排列,每一种状态都是一种排列,就可以用康托展开来压缩所有状态,只需开一个大小为9!=362880的数组来存储是否出现重复情况即可。然后康托展开求阶乘没必要一个一个循环,可以用秦九韶算法4*4!+2*3!+2*2!=113(((4*4+2)*3+2)*2+1)*1=113Have[ ][ ]存储某种状态是否存在Line[ ][ ]存储双向宽搜的状态Last[ ][ ]存储上一种状态的编号,用来输出路径Len[ ]存储双向宽搜的已有状态数Mid[ ]找到的答案Now[ ]存储当前搜索到的八数码的状态Line[0][ ]和line[1][ ]分别为两条队列Line[0][now[0]],Line[1][now[1]]为队列的首元素Line[0][len[0]],Line[1][len[1]]为队列尾元素*/#include<iostream>#include<cstdio>using namespace std;#define MAXN 370000int s[10],line[2][MAXN],len[2],now[2],have[2][MAXN],mid[2],last[2][MAXN],NUM;int p;int turn(){ int result=0; for(int i=0;i<9;i++){ result*=10; result+=s[i]; } return result;}int cantor(){ int a=0,b=0; for(int i=8;i>=1;i--){//从后往前枚举每个数 int b=s[i]; for(int j=8;j>i;j--){//枚举这个数后面的数 if(s[j]<s[i])--b; } a+=b; a*=i; } return a;}void get(int num){ for(int i=8;i>=0;i--){ s[i]=num%10; if(s[i]==0)p=i; num/=10; }}void go(int c,int w){ int temp=0,num=0; temp=s[p];s[p]=s[p+c];s[p+c]=temp; ++len[w]; line[w][len[w]]=turn(); num=cantor(); if(have[w][num]!=0)--len[w]; else{ last[w][len[w]]=now[w]; if(have[!w][num]!=0){ mid[w]=len[w]; mid[!w]=have[!w][num]; } else have[w][num]=len[w]; } temp=s[p];s[p]=s[p+c];s[p+c]=temp;}void out(){ NUM++; /*int cnt=0; for(int i=1;i<=3;i++){ for(int j=1;j<=3;j++){ cout<<s[cnt];cnt++; }cout<<endl; } cout<<endl;*/}void out1(int num){ if(num!=1){ out1(last[0][num]); //cout<<"\n"; } get(line[0][num]); out();}void out2(int num){ get(line[1][num]); if(num!=mid[1]) out(); if(num!=1){ //cout<<"\n"; out2(last[1][num]); }}int main(){ char ch[10]; cin>>ch; for(int i=0;i<9;i++) s[i]=ch[i]-'0'; int shu=turn(); int kang=cantor(); line[0][1]=shu;//正向bfs的第一个状态是初始状态 len[0]=1;now[0]=1;have[0][kang]=1; s[0]=1;s[1]=2;s[2]=3;s[3]=8;s[4]=0;s[5]=4;s[6]=7;s[7]=6;s[8]=5; shu=turn(); kang=cantor(); line[1][1]=shu;//反向bfs的第一个状态是目标状态 len[1]=1;now[1]=1; if(have[0][kang]==0)have[1][kang]=1; else{ cout<<0<<endl; } while(mid[0]==0&&(now[0]<=len[0]||now[1]<=len[1])){//还没出答案,继续搜 while(mid[0]==0&&len[1]>=len[0]&&now[0]<=len[0]){//反向bfs的状态数多于正向bfs,就着手正向bfs get(line[0][now[0]]); //讨论0的位置 if(p>=3&&mid[0]==0)go(-3,0);//在后两行,可以上移 if(p<=5&&mid[0]==0)go(3,0);//在前两行,可以下移 if(mid[0]==0&&p>=1&&(p-1)%3!=2)go(-1,0);//在右两列,可以左移 if(mid[0]==0&&p<=8&&(p+1)%3!=0)go(1,0);//在左两列,可以右移 ++now[0]; } while(mid[0]==0&&len[0]>=len[1]&&now[1]<=len[1]){ get(line[1][now[1]]); if(p>=3&&mid[1]==0)go(-3,1); if(p<=5&&mid[1]==0)go(3,1); if(mid[1]==0&&p>=1&&(p-1)%3!=2)go(-1,1); if(mid[1]==0&&p<=8&&(p+1)%3!=0)go(1,1); ++now[1]; } } out1(mid[0]); out2(mid[1]); cout<<NUM-1;}
0 0
- 八数码难题 洛谷1379
- 洛谷P1379 八数码难题
- 洛谷 P1379 八数码难题
- 洛谷 P1379 八数码难题
- 洛谷 P1379 八数码难题
- 洛谷 P1379 八数码难题
- 洛谷 P1379 八数码难题
- BFS+康托展开(洛谷1379 八数码难题)
- IDA*-洛谷P1379 八数码难题
- 八数码难题源代码
- 【宽搜】八数码难题
- wikioi1225 八数码难题
- wikioi1225 八数码难题
- ## 八数码难题 ##
- Codevs1225 八数码难题
- 八数码难题
- 八数码难题
- 八数码难题
- python-网络爬虫初学一:获取网页源码以及发送POST和GET请求
- codevs 3342绿色通道
- mac 开发必备软件(不断update ing...)
- 可爱的猴子
- Gson 和 Fastjson 你不知道的事
- 八数码难题 洛谷1379
- Sql优化方法
- Mysql tinyint smallint int bigint 区别
- codevs2924 数独挑战
- 将博客搬至CSDN
- 关于Python2.X与Python3.X的编码问题
- UML系列图--用例图
- codevs 1004 四子连棋
- ELKStack 基础介绍之 Logstash [三]