天天看點

廣度優先搜尋與八字碼問題

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