广度优先搜索算法(Breadth-First Search),又称为"宽度优先搜索"或"横向优先搜索"主要可以解决两类问题:
·是否存在从起点到终点的路径
·找出从起点到终点的最短路径a
算法描述:
1 int bfs(){
2 初始化 首结点入队(首指针为0,尾指针为1)
3 while(首指针小于尾指针){
4 首指针后移一位
5 for(;;) { 产生子结点
6 if() { 判断子结点是否满足条件
7 if(){ 如果结点未与之前产生过重复
8 尾指针后移
9 存入新的结点 (提供结点的父结点和层数)
10 if(){ 如果新结点是目标节点
11 输出并退出
12 }
13 }
14 }
15 }
16 }
17 }
值得注意的是,广搜的过程中每生成一个子结点,都要提供指向他们的父结点的指针和层数,以免找到解的时候找不到来时的路径。
广度优先搜索在访问完该层的所有结点后,才开始访问下一层
关于从搜索树通过队列存入数组的思想:
广搜一定要将生成的结点与之前的比较,以免出现重复的节点,浪费时间和空间,还有可能陷入死循环!

八字码问题
Description
The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 x
where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
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->
The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.
Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).
In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.
Input
You will receive a description of a configuration of the 8 puzzle. The description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus 'x'. For example, this puzzle
1 2 3
x 4 6
7 5 8
is described by this list:
1 2 3 x 4 6 7 5 8
Output
You will print to standard output either the word ``unsolvable'', if the puzzle has no solution, or a string consisting entirely of the letters 'r', 'l', 'u' and 'd' that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line.
Sample Input
2 3 4 1 5 x 7 6 8
Sample Output
ullddrurdllurdr
这道题的思路大概是这样子
1.读入到a数组内
2.输出一下a数组 做一个子程序 print2
3.定义一下宽搜的节点
1)首先有一个a棋盘(是一个二维数组)
2)移动空位,记住空位的位置x,y
3)记录深度(你走了几步)叫dep
4)父节点,打方案用,走法dd
4.定义队列大数组结构体data1 100000 一个头指针op,尾指针cl
5.偏移量,空位的移动方案d[5]结构体d[1].x d[1].y偏移
6.初始化队列 首节点入队(初始状态) 写一个拷贝子程序
7.做一个棋盘之间的复制 copy(a,b) 把a棋盘的值拷贝到b棋盘
8.判断两个棋盘的值是否相同
9.判断队列中棋盘是否存在 exist(a) a棋盘在我的data1数组中从1到cl是否存在
10.输出方案的子程序print1
11.写宽搜的框架
但这个时候问题来了,单项搜索的效率太低了!!!如果要走20步,程序需要运行8秒多!!!
这个时候,我们会发现题目中给出了终态! 在这种情况下,同样的搜索从初态和终态出发各搜索一半状态,产生两棵深度减半的搜索树,在中间交会、组合成最终的答案。
这种算法的时间复杂度只有O(2N/2log2n/2)=O(N*2N/2)!!!
这道题是不是完美地解决了??
等等! 还有unsolvable的判断!但是这道题不能用搜索来判断是否有解------无解的时候程序将无限的搜索下去!!
这个时候就需要事先判断八个数字的排列了。
我们会用到置换:
在组合数学中,置换一词的传统意义是一个有序序列,其中元素不重复,但可能有阙漏。例如1,2,4,3可以称为1,2,3,4,5,6的一个置换,但是其中不含5,6。此时通常会标明为“从n个对象取r个对象的置换”。
轮换长度为偶数的轮换称为偶轮换,反之则为奇轮换;由此可定义任一置换的奇偶性,并可证明:一个置换是偶置换的充要条件是它可以由偶数个换位生成。偶轮换在置换群中构成一个正规子群,称为交错群。
(摘自百度百科)
也就是说,我们可以统计排列中逆序的次数(即后一项小于前一项,0不计),如果有奇数次,则无解。
举个栗子叭
1 | 2 | 3 |
5 | 4 | 7 |
8 | 6 |
4<5 , 6<7 , 6<8 一共有三次逆序,所以无解.
双向搜索代码
1 #include<cstdio>
2 #include<iostream>
3 #include<string>
4 #include<cstring>
5 using namespace std;
6 int a[4][4]={},c[4][4]={},x1,y1,x,y,op=0,cl=1,op1=0,cl1=1,dep=0,dep1=0; //op1 cl1表示由答案开始搜索的队列
7 int ii,jj;
8 int a1[10]={}; //用于判断unsolvable
9 char k,answer[100];
10 int ans[4][4]={{1,2,3,0},{4,5,6,0},{7,8,0,0},{0,0,0,0}};
11 void input(int a[4][4]){
12 for(int i=0;i<3;i++){
13 for(int j=0;j<3;j++){
14 cin>>k;
15 if(k=='x') {a[i][j]=0;x=i;y=j;}
16 else {
17 a[i][j]=k-'0';
18 a1[i*3+j]=a[i][j];
19 }
20 }
21 }
22 }
23 void print2(int a[4][4]){
24 for(int i=0;i<3;i++){
25 for(int j=0;j<3;j++)
26 printf("%d ",a[i][j]);
27 printf("\n");
28 }
29 }
30 void copy(int a[4][4],int b[4][4]){
31 for(int i=0;i<3;i++){
32 for(int j=0;j<3;j++)
33 b[i][j]=a[i][j];
34 }
35 }
36 bool same(int a[4][4],int b[4][4]){
37 for(int i=0;i<3;i++){
38 for(int j=0;j<3;j++)
39 if(b[i][j]!=a[i][j]) return false;
40 }
41 return true;
42 }
43
44 struct node1{
45 int x,y;
46 }d[5]={{0,0},{-1,0},{+1,0},{0,-1},{0,+1}};
47 struct node2{
48 int m[4][4];
49 int dep; //结点深度
50 int dd; //行走方向
51 int x,y; //坐标
52 int fa; //父结点下标
53 }data1[100001];
54 struct node3{
55 int m[4][4];
56 int dep; //结点深度
57 int dd; //行走方向
58 int x,y; //坐标
59 int fa; //父结点下标
60 }data2[100001];
61 bool exist(int a[4][4]){
62 for(int i=0;i<=cl;i++){
63 if(same(data1[i].m,a)) return false;
64 }
65 return true;
66 }
67 bool exist1(int a[4][4]){
68 for(int i=0;i<=cl1;i++){
69 if(same(data2[i].m,a)) return false;
70 }
71 return true;
72 }
73 void print1(int cl, int cl1){
74 int kk=cl,num=0;
75 while(dep--){
76 if(data1[kk].dd==1) answer[num++]='u';
77 else if(data1[kk].dd==2) answer[num++]='d';
78 else if(data1[kk].dd==3) answer[num++]='l';
79 else if(data1[kk].dd==4) answer[num++]='r';
80 kk=data1[kk].fa;
81 }
82 for(int i=num-1;i>=0;i--) printf("%c",answer[i]);
83 kk=cl1; num=0;
84 while(dep1--){
85 if(data2[kk].dd==1) answer[num++]='u';
86 else if(data2[kk].dd==2) answer[num++]='d';
87 else if(data2[kk].dd==3) answer[num++]='l';
88 else if(data2[kk].dd==4) answer[num++]='r';
89 kk=data2[kk].fa;
90 }
91 for(int i=0;i<num;i++) printf("%c",answer[i]);
92 printf("\n");
93 }
94
95 int main(){
96 // freopen("Eight.in","r",stdin);
97 //输入
98 input(a);
99 //特判
100 if(same(a,ans)){
101 printf("%d\n",0);
102 return 0;
103 }
104 int sum1=0;
105 for(int i=1;i<9;i++)
106 if (a1[i]!=0){
107 for (int j=i+1; j<9; ++j)
108 if (a1[i]>a1[j] && a1[j]!=0) {
109 ++sum1;
110 }
111 }
112
113 if (sum1%2==0){
114 printf("unsolvable\n");
115 return 0;
116 }
117
118 //首结点入队
119 data1[1].dd=0;
120 data1[1].dep=1;
121 data1[1].x=x;
122 data1[1].y=y;
123 data1[1].fa=-1;
124 copy(a,data1[1].m);
125
126 data2[1].dd=0;
127 data2[1].dep=1;
128 data2[1].x=2;
129 data2[1].y=2;
130 data2[1].fa=-1;
131 copy(ans,data2[1].m);
132 //宽搜
133 while(op<=cl){
134
135 op++; op1++;
136 if(dep!=data1[op].dep){
137 for(int i=1;i<=cl;i++){
138 for(int j=1;j<=cl1;j++){
139 if(data1[i].dep==dep){
140 if(same(data1[i].m,data2[j].m)){
141 print1(i,j); return 0;
142 }
143 }
144 }
145 }
146 }
147 dep=data1[op].dep;
148 for(int i=1;i<=4;i++){
149 x=data1[op].x+d[i].x;
150 y=data1[op].y+d[i].y;
151 if(x>=0 && x<3 && y>=0 && y<3){
152 //printf("\n%d %d %d\n",op,x,y);
153 //移动后的棋盘存给c
154 copy(data1[op].m,c);
155 c[data1[op].x][data1[op].y]=c[x][y];
156 c[x][y]=0;
157 if(exist(c)){
158 cl++;
159 data1[cl].dd=i;
160 data1[cl].dep=dep+1;
161 data1[cl].x=x;
162 data1[cl].y=y;
163 data1[cl].fa=op;
164 copy(c,data1[cl].m);
165 }
166 }
167 }
168 dep1=data2[op1].dep;
169 for(int i=1;i<=4;i++){
170 x=data2[op1].x+d[i].x;
171 y=data2[op1].y+d[i].y;
172 if(x>=0 && x<3 && y>=0 && y<3){
173 copy(data2[op1].m,c);
174 c[data2[op1].x][data2[op1].y]=c[x][y];
175 c[x][y]=0;
176 if(exist1(c)){
177 cl1++;
178 data2[cl1].dd=i;
179 data2[cl1].dep=dep1+1;
180 data2[cl1].x=x;
181 data2[cl1].y=y;
182 data2[cl1].fa=op;
183 copy(c,data2[cl1].m);
184 }
185 }
186 }
187 }
188 return 0;
189 }
转载于:https://www.cnblogs.com/hnoi/p/10922680.html