八数码难题解法大全
时间:2022-05-08
本文章向大家介绍八数码难题解法大全,主要内容包括暂时弃坑,双向广搜太难写了。。。。、https://www.luogu.org/problem/show?pid=1379、BFS+map+常数优化、BFS+hash、BFS+hash+逆向搜索、A*、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
暂时弃坑,双向广搜太难写了。。。。
https://www.luogu.org/problem/show?pid=1379
突然发现八数码难题挺有意思的
貌似关于这一个问题就能延伸出好多种算法
挖个坑,慢慢填2333
BFS+map
第一发
裸的BFS
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<queue>
5 #include<map>
6 #include<cstdlib>
7 using namespace std;
8 const int n=3;
9 inline void read(int &n)
10 {
11 char c=getchar();bool flag=0;n=0;
12 while(c<'0'||c>'9') c=='-'?flag=1,c=getchar():c=getchar();
13 while(c>='0'&&c<='9') n=n*10+c-48,c=getchar();flag==1?n=-n:n=n;
14 }
15 map<string,bool>vis;
16 struct node
17 {
18 int a[4][4];
19 int step;
20 }cur,nxt,ed;
21 inline void debug(node p)
22 {
23 printf("***********n");
24 for(int i=1;i<=n;i++)
25 {
26 for(int j=1;j<=n;j++)
27 printf("%d ",p.a[i][j]);
28 putchar('n');
29 }
30 printf("***********n");
31 }
32 int xx[5]={-1,+1,0,0};
33 int yy[5]={0,0,-1,+1};
34 bool pd(node p)
35 {
36 string s;
37 for(int i=1;i<=n;i++)
38 for(int j=1;j<=n;j++)
39 s=s+(char)(p.a[i][j]-48);
40 if(vis[s]==0){ vis[s]=1;return 0; }
41 else return 1;
42 }
43 bool findans(node p)
44 {
45 for(int i=1;i<=n;i++)
46 for(int j=1;j<=n;j++)
47 if(p.a[i][j]!=ed.a[i][j]) return 0;
48 return 1;
49 }
50 inline void BFS()
51 {
52 queue<node>q;
53 q.push(cur);
54 while(q.size()!=0)
55 {
56 node p=q.front();
57 //debug(p);
58 if(findans(p)==1)
59 {
60 printf("%d",p.step);
61 exit(0);
62 }
63 q.pop();
64 bool flag=0;
65 for(int i=1;i<=n;i++)
66 {
67 for(int j=1;j<=n;j++)
68 {
69 if(p.a[i][j]==0)
70 {
71 for(int k=0;k<4;k++)
72 {
73 int wx=i+xx[k];
74 int wy=j+yy[k];
75 if(wx>=1&&wx<=n&&wy>=1&&wy<=n)
76 {
77 node nxt=p;
78 swap(nxt.a[i][j],nxt.a[wx][wy]);
79 nxt.step=p.step+1;
80 if( pd(nxt) == 0 )
81 q.push(nxt);
82 }
83 }
84 flag=1;break;
85 }
86 }
87 if(flag==1) break;
88 }
89
90 }
91 }
92 int main()
93 {
94 ed.a[1][1]=1;ed.a[1][2]=2;ed.a[1][3]=3;ed.a[2][1]=8;ed.a[2][2]=0;ed.a[2][3]=4;ed.a[3][1]=7;ed.a[3][2]=6;ed.a[3][3]=5;
95 for(int i=1;i<=n;i++)
96 for(int j=1;j<=n;j++)
97 { char c=getchar();cur.a[i][j]=c-48; }
98 cur.step=0;
99 BFS();
100 return 0;
101 }
第一次
第二次
第三次
慢的一逼。。
第二次TLE了5个点,,
表示实在无力吐槽啊。。。
我的代码有这么丑么???
不行!我要优化!!
BFS+map+常数优化
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<queue>
5 #include<map>
6 #include<cstdlib>
7 using namespace std;
8 const int n=3;
9 inline void read(int &n)
10 {
11 char c=getchar();bool flag=0;n=0;
12 while(c<'0'||c>'9') c=='-'?flag=1,c=getchar():c=getchar();
13 while(c>='0'&&c<='9') n=n*10+c-48,c=getchar();flag==1?n=-n:n=n;
14 }
15 map<string,bool>vis;
16 struct node
17 {
18 int a[4][4];
19 int step;
20 int zerox,zeroy;
21 }cur,nxt,ed;
22 inline void debug(node p)
23 {
24 printf("***********n");
25 for(int i=1;i<=n;i++)
26 {
27 for(int j=1;j<=n;j++)
28 printf("%d ",p.a[i][j]);
29 putchar('n');
30 }
31 printf("***********n");
32 }
33 int xx[5]={-1,+1,0,0};
34 int yy[5]={0,0,-1,+1};
35 bool pd(node p)
36 {
37 string s;
38 for(int i=1;i<=n;i++)
39 for(int j=1;j<=n;j++)
40 s=s+(char)(p.a[i][j]-48);
41 if(vis[s]==0){ vis[s]=1;return 0; }
42 else return 1;
43 }
44 bool findans(node p)
45 {
46 for(int i=1;i<=n;i++)
47 for(int j=1;j<=n;j++)
48 if(p.a[i][j]!=ed.a[i][j]) return 0;
49 return 1;
50 }
51 inline void BFS()
52 {
53 queue<node>q;
54 q.push(cur);
55 while(q.size()!=0)
56 {
57 node p=q.front();
58 //debug(p);
59 if(findans(p)==1)
60 {
61 printf("%d",p.step);
62 exit(0);
63 }
64 q.pop();
65 bool flag=0;
66 for(int k=0;k<4;k++)
67 {
68 int wx=p.zerox+xx[k];
69 int wy=p.zeroy+yy[k];
70 if(wx>=1&&wx<=n&&wy>=1&&wy<=n)
71 {
72 node nxt=p;
73 swap(nxt.a[p.zerox][p.zeroy],nxt.a[wx][wy]);
74 nxt.step=p.step+1;
75 nxt.zerox=wx;nxt.zeroy=wy;
76 if( pd(nxt) == 0 )
77 q.push(nxt);
78 }
79 }
80 }
81 }
82 int main()
83 {
84 ed.a[1][1]=1;ed.a[1][2]=2;ed.a[1][3]=3;ed.a[2][1]=8;ed.a[2][2]=0;ed.a[2][3]=4;ed.a[3][1]=7;ed.a[3][2]=6;ed.a[3][3]=5;
85 for(int i=1;i<=n;i++)
86 for(int j=1;j<=n;j++)
87 { char c=getchar();cur.a[i][j]=c-48;
88 if(c=='0') cur.zerox=i,cur.zeroy=j;
89 }
90 cur.step=0;
91 BFS();
92 return 0;
93 }
这次我把寻找0的位置的循环给去掉了,
用两个变量来记录0的位置,用空间换时间
第一次
第二次
第三次
WTF?????
卵用没有????
=.=。。。。。
=.=。。。。。,,,,
看来常数优化是没怎么有用了
尝试优化一下STL吧
BFS+hash
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<queue>
5 #include<map>
6 #include<cstdlib>
7 using namespace std;
8 const int n=3;
9 inline void read(int &n)
10 {
11 char c=getchar();bool flag=0;n=0;
12 while(c<'0'||c>'9') c=='-'?flag=1,c=getchar():c=getchar();
13 while(c>='0'&&c<='9') n=n*10+c-48,c=getchar();flag==1?n=-n:n=n;
14 }
15 struct node
16 {
17 int a[4][4];
18 int step;
19 int zerox,zeroy;
20 }cur,nxt,ed;
21 inline void debug(node p)
22 {
23 printf("***********n");
24 for(int i=1;i<=n;i++)
25 {
26 for(int j=1;j<=n;j++)
27 printf("%d ",p.a[i][j]);
28 putchar('n');
29 }
30 printf("***********n");
31 }
32 int xx[5]={-1,+1,0,0};
33 int yy[5]={0,0,-1,+1};
34 int vis[37338030];
35 bool pd(node p)
36 {
37 unsigned int seed=0;
38 unsigned long long k=1;
39 for(int i=1;i<=n;i++)
40 for(int j=1;j<=n;j++)
41 seed=seed+p.a[i][j]*k,k=k*9;
42 seed=(seed%3733801);
43 if(vis[seed]==0){ vis[seed]=1;return 0; }
44 else return 1;
45 }
46 bool findans(node p)
47 {
48 for(int i=1;i<=n;i++)
49 for(int j=1;j<=n;j++)
50 if(p.a[i][j]!=ed.a[i][j]) return 0;
51 return 1;
52 }
53 inline void BFS()
54 {
55 queue<node>q;
56 q.push(cur);
57 while(q.size()!=0)
58 {
59 node p=q.front();
60 //debug(p);
61 if(findans(p)==1)
62 {
63 printf("%d",p.
64 step);
65 exit(0);
66 }
67 q.pop();
68 bool flag=0;
69 for(int k=0;k<4;k++)
70 {
71 int wx=p.zerox+xx[k];
72 int wy=p.zeroy+yy[k];
73 if(wx>=1&&wx<=n&&wy>=1&&wy<=n)
74 {
75 node nxt=p;
76 swap(nxt.a[p.zerox][p.zeroy],nxt.a[wx][wy]);
77 nxt.step=p.step+1;
78 nxt.zerox=wx;nxt.zeroy=wy;
79 if( pd(nxt) == 0 )
80 q.push(nxt);
81 }
82 }
83 }
84 }
85 int main()
86 {
87 ed.a[1][1]=1;ed.a[1][2]=2;ed.a[1][3]=3;ed.a[2][1]=8;ed.a[2][2]=0;ed.a[2][3]=4;ed.a[3][1]=7;ed.a[3][2]=6;ed.a[3][3]=5;
88 for(int i=1;i<=n;i++)
89 for(int j=1;j<=n;j++)
90 { char c=getchar();cur.a[i][j]=c-48;
91 if(c=='0') cur.zerox=i,cur.zeroy=j;
92 }
93 cur.step=0;
94 BFS();
95 return 0;
96 }
果断把map改成hash
老师说过map慢的一逼
第一次
第二次
第三次
O__O" O__O" O__O" O__O"
O__O" O__O" O__O" O__O"
O__O" O__O" O__O" O__O"
O__O" O__O" O__O" O__O"
O__O" O__O" O__O" O__O"
=.=...
发生了什么,,,我只不过是优化了一个理论上的log而已=.=。。
不会吧,,,,,
我以前可都是用map+string判重的。。。
我感觉我需要重新认识一下这个世界了。。。。
zhx老师说过倒着搜会有神奇的效果。
不如试一试?
BFS+hash+逆向搜索
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<queue>
5 #include<map>
6 #include<cstdlib>
7 using namespace std;
8 const int n=3;
9 inline void read(int &n)
10 {
11 char c=getchar();bool flag=0;n=0;
12 while(c<'0'||c>'9') c=='-'?flag=1,c=getchar():c=getchar();
13 while(c>='0'&&c<='9') n=n*10+c-48,c=getchar();flag==1?n=-n:n=n;
14 }
15 struct node
16 {
17 int a[4][4];
18 int step;
19 int zerox,zeroy;
20 }cur,nxt,ed;
21 inline void debug(node p)
22 {
23 printf("***********n");
24 for(int i=1;i<=n;i++)
25 {
26 for(int j=1;j<=n;j++)
27 printf("%d ",p.a[i][j]);
28 putchar('n');
29 }
30 printf("***********n");
31 }
32 int xx[5]={-1,+1,0,0};
33 int yy[5]={0,0,-1,+1};
34 int vis[5733801];
35 bool pd(node p)
36 {
37 unsigned int seed=0;
38 unsigned long long k=1;
39 for(int i=1;i<=n;i++)
40 for(int j=1;j<=n;j++)
41 seed=seed+p.a[i][j]*k,k=k*71;
42 seed=(seed%5733801);
43 if(vis[seed]==0){ vis[seed]=1;return 0; }
44 else return 1;
45 }
46 bool findans(node p)
47 {
48 for(int i=1;i<=n;i++)
49 for(int j=1;j<=n;j++)
50 if(p.a[i][j]!=ed.a[i][j]) return 0;
51 return 1;
52 }
53 inline void BFS()
54 {
55 queue<node>q;
56 q.push(cur);
57 while(q.size()!=0)
58 {
59 node p=q.front();
60 //debug(p);
61 if(findans(p)==1)
62 {
63 printf("%d",p.
64 step);
65 exit(0);
66 }
67 q.pop();
68 bool flag=0;
69 for(int k=0;k<4;k++)
70 {
71 int wx=p.zerox+xx[k];
72 int wy=p.zeroy+yy[k];
73 if(wx>=1&&wx<=n&&wy>=1&&wy<=n)
74 {
75 node nxt=p;
76 swap(nxt.a[p.zerox][p.zeroy],nxt.a[wx][wy]);
77 nxt.step=p.step+1;
78 nxt.zerox=wx;nxt.zeroy=wy;
79 if( pd(nxt) == 0 )
80 q.push(nxt);
81 }
82 }
83 }
84 }
85 int main()
86 {
87 ed.a[1][1]=1;ed.a[1][2]=2;ed.a[1][3]=3;ed.a[2][1]=8;ed.a[2][2]=0;ed.a[2][3]=4;ed.a[3][1]=7;ed.a[3][2]=6;ed.a[3][3]=5;
88 ed.zerox=2;ed.zeroy=2;
89 for(int i=1;i<=n;i++)
90 for(int j=1;j<=n;j++)
91 { char c=getchar();cur.a[i][j]=c-48;
92 if(c=='0') cur.zerox=i,cur.zeroy=j;
93 }
94 swap(ed,cur);
95 cur.step=0;
96 BFS();
97 return 0;
98 }
时间复杂度应该是差不多的
看来需要从算法上进行优化了
A*
一种比较神奇的算法,关于他的介绍可以看http://blog.csdn.net/zgwangbo/article/details/52078338
对于这道题来说,我们可以枚举一个希望的值,再进行枚举
注意枚举的时候要用DFS,因为BFS不好记录状态
裸的A*
(无视ID)
雾。。。
和爆搜差不多,,,
我的代码有这么丑么。。。。
拆开结构体
貌似快了一些
把变量加到dfs的参数中
好像又快了一些。。。
但还是比估计的慢很多
真相大白
我去!!
我终于知道为什么慢了
我在取绝对值的时候是用的自己手写的fabs
用了algorithm库里面的之后快了接近300ms!
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 #include<cmath>
6 using namespace std;
7 const int n=3;
8 inline void read(int &n)
9 {
10 char c=getchar();bool flag=0;n=0;
11 while(c<'0'||c>'9') c=='-'?flag=1,c=getchar():c=getchar();
12 while(c>='0'&&c<='9') n=n*10+c-48,c=getchar();flag==1?n=-n:n=n;
13 }
14 int xx[4]={0,1,-1,0};
15 int yy[4]={1,0,0,-1};
16 int fx[11]={0,1,1,1,2,3,3,3,2};
17 int fy[11]={0,1,2,3,3,3,2,1,1};// fx[i] fy[j]表示的是目标状态下i数码的位置
18 int a[4][4];
19 int check()
20 {
21 int now=0;
22 for(int i=1;i<=3;i++)
23 for(int j=1;j<=3;j++)
24 if(a[i][j])
25 now+=abs(i-fx[a[i][j]])+abs(j-fy[a[i][j]]);
26 return now;
27 }
28 int ans=0;
29 void dfs(int k,int zerox,int zeroy,int step)
30 {
31 int h=check();
32 if(h==0)
33 {
34 ans=step;return ;
35 }
36 if(h+step>k||ans||step==k) return ;
37 for(int i=0;i<4;i++)
38 {
39 int wx=zerox+xx[i];
40 int wy=zeroy+yy[i];
41 if(wx>=1&&wx<=n&&wy>=1&&wy<=n)
42 {
43 swap(a[zerox][zeroy],a[wx][wy]);
44 dfs(k,wx,wy,step+1);
45 swap(a[zerox][zeroy],a[wx][wy]);
46 }
47 }
48 }
49 int main()
50 {
51 int zerox,zeroy,k=0;
52 char c;
53 for(int i=1;i<=n;i++)
54 for(int j=1;j<=n;j++)
55 { scanf("%c",&c);a[i][j]=c-48;
56 if(c=='0') zerox=i,zeroy=j;}
57 while(++k&&ans==0)
58 dfs(k,zerox,zeroy,0);
59 printf("%d",ans);
60 return 0;
61 }
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- linux DMA接口知识点详解
- Linux中使用crond工具创建定时任务的方法
- Linux which命令的具体使用
- Linux安装Python3.8.1的教程详解
- linux压缩文件命令zip的实例用法
- centos下samba文件夹共享服务器配置详解
- Centos7安装FFmpeg音/视频工具简易文档
- Linux 进程通信之FIFO的实现
- Linux nl命令的使用方法
- Linux gcc命令的具体使用
- Linux dirname命令的具体使用
- Linux 相对路径和绝对路径的使用
- Linux basename命令的使用方法
- 在Ubuntu上搭建一个基于webrtc的多人视频聊天服务实例代码详解
- linux中权限管理命令详解(chmod/chown/chgrp/unmask)