廣度優先搜尋算法(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