洛谷OJ P1379 八数码难题 解题报告

洛谷OJ P1379 八数码难题 解题报告

by MedalPluS

  题目描述

  在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

  输入格式

  输入初试状态,一行九个数字,空格用0表示

  输出格式

  只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

  分析

  其实就是个裸的BFS,但是可以拓展很多知识点(有人说不做这题的人的OI人生不完美)

  暴力BFS的话会被卡,因为要搜索的状态实在太多了

  所以这里有两种优化:

  1.启发式搜索

  我们假设f=g+h,那么g可以设为已经挪动的步数,h为不在位将牌个数,这样就构建了一个估价函数

  然后直接写就好

  2.双向BFS

  我们知道起点和终点,直接双向就好

  另外,这里应该如何判重呢?其实很简单,下面引入康托展开:http://blog.csdn.net/u010372095/article/details/9904497

  然后就利用康托值进行判重就好

 

  代码

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <queue>
  4 #include <cstdlib>
  5 using namespace std;
  6 
  7 #define rep(i,l,r) for(i=l;i<=r;i++)
  8 const int maxn=10;
  9 const int maxm=1000001;//9!*8+8!*7...<=5000001
 10 
 11 struct node{
 12     int a[maxn][maxn];
 13     short int g;
 14     node(){g=0;}
 15 }Head,Tail;
 16 
 17 short int vis_f[maxm],vis_b[maxm];
 18 int tmps[maxn];
 19 queue<node> f,b;
 20 
 21 int fact(int x){
 22     int ans;
 23     for(ans=1;x>=2;x--)ans*=x;
 24     return ans;
 25 }
 26 
 27 int Cantor(node now){//Cantor_Expand
 28     int i,j,t=0,res=0;
 29     rep(i,1,3)
 30       rep(j,1,3)
 31         tmps[t++]=now.a[i][j];
 32     t=0;
 33     rep(i,0,8)
 34     {
 35         t=0;
 36         rep(j,i+1,8)
 37           if(tmps[j]<tmps[i])
 38             t++;
 39         res+=t*fact(9-i-1);
 40     }
 41     return res;
 42 }
 43 
 44 void init_Front(){
 45     Head.a[1][1]=1;Head.a[1][2]=2;Head.a[1][3]=3;
 46     Head.a[2][1]=8;Head.a[2][2]=0;Head.a[2][3]=4;
 47     Head.a[3][1]=7;Head.a[3][2]=6;Head.a[3][3]=5;
 48     Head.g=0;
 49 }
 50 
 51 void init_Back(){
 52     int i,j;
 53     rep(i,1,3)
 54       rep(j,1,3)
 55         scanf("%1d",&Tail.a[i][j]);
 56 }
 57 
 58 void init(){
 59     memset(vis_f,-1,sizeof(vis_f));
 60     memset(vis_b,-1,sizeof(vis_b));
 61     init_Front();
 62     init_Back();
 63 }
 64 
 65 void expand_f(){
 66     node head,tmp;
 67     head=f.front();
 68     f.pop();
 69     int i,j,sx,sy;
 70     rep(i,1,3)
 71       rep(j,1,3)
 72         if(!head.a[i][j])
 73         {
 74           sx=i;
 75           sy=j;
 76           break;
 77         }
 78     tmp=head;
 79     if(sx-1>0){
 80         swap(tmp.a[sx-1][sy],tmp.a[sx][sy]);
 81         tmp.g++;
 82         if(vis_b[Cantor(tmp)]!=-1){cout<<tmp.g+vis_b[Cantor(tmp)];exit(0);}
 83         if(vis_f[Cantor(tmp)]==-1){
 84           vis_f[Cantor(tmp)]=tmp.g;
 85           f.push(tmp);
 86         }
 87     }
 88     tmp=head;
 89     if(sx+1<=3){
 90         swap(tmp.a[sx+1][sy],tmp.a[sx][sy]);
 91         tmp.g++;
 92         if(vis_b[Cantor(tmp)]!=-1){cout<<tmp.g+vis_b[Cantor(tmp)];exit(0);}
 93         if(vis_f[Cantor(tmp)]==-1){
 94           vis_f[Cantor(tmp)]=tmp.g;
 95           f.push(tmp);
 96         }
 97     }
 98     tmp=head;
 99     if(sy-1>0){
100         swap(tmp.a[sx][sy-1],tmp.a[sx][sy]);
101         tmp.g++;
102         if(vis_b[Cantor(tmp)]!=-1){cout<<tmp.g+vis_b[Cantor(tmp)];exit(0);}
103         if(vis_f[Cantor(tmp)]==-1){
104           vis_f[Cantor(tmp)]=tmp.g;
105           f.push(tmp);
106         }
107     }
108     tmp=head;
109     if(sy+1<=3){
110         swap(tmp.a[sx][sy+1],tmp.a[sx][sy]);
111         tmp.g++;
112         if(vis_b[Cantor(tmp)]!=-1){cout<<tmp.g+vis_b[Cantor(tmp)];exit(0);}
113         if(vis_f[Cantor(tmp)]==-1){
114           vis_f[Cantor(tmp)]=tmp.g;
115           f.push(tmp);
116         }
117     }
118 }
119 
120 void expand_b(){
121     node head,tmp;
122     head=b.front();
123     b.pop();
124     int i,j,sx,sy;
125     rep(i,1,3)
126       rep(j,1,3)
127         if(!head.a[i][j])
128         {
129           sx=i;
130           sy=j;
131           break;
132         }
133     tmp=head;
134     if(sx-1>0){
135         swap(tmp.a[sx-1][sy],tmp.a[sx][sy]);
136         tmp.g++;
137         if(vis_f[Cantor(tmp)]!=-1){cout<<tmp.g+vis_f[Cantor(tmp)];exit(0);}
138         if(vis_b[Cantor(tmp)]==-1){
139           vis_b[Cantor(tmp)]=tmp.g;
140           b.push(tmp);
141         }
142     }
143     tmp=head;
144     if(sx+1<=3){
145         swap(tmp.a[sx+1][sy],tmp.a[sx][sy]);
146         tmp.g++;
147         if(vis_f[Cantor(tmp)]!=-1){cout<<tmp.g+vis_f[Cantor(tmp)];exit(0);}
148         if(vis_b[Cantor(tmp)]==-1){
149           vis_b[Cantor(tmp)]=tmp.g;
150           b.push(tmp);
151         }
152     }
153     tmp=head;
154     if(sy-1>0){
155         swap(tmp.a[sx][sy-1],tmp.a[sx][sy]);
156         tmp.g++;
157         if(vis_f[Cantor(tmp)]!=-1){cout<<tmp.g+vis_f[Cantor(tmp)];exit(0);}
158         if(vis_b[Cantor(tmp)]==-1){
159           vis_b[Cantor(tmp)]=tmp.g;
160           b.push(tmp);
161         }
162     }
163     tmp=head;
164     if(sy+1<=3){
165         swap(tmp.a[sx][sy+1],tmp.a[sx][sy]);
166         tmp.g++;
167         if(vis_f[Cantor(tmp)]!=-1){cout<<tmp.g+vis_f[Cantor(tmp)];exit(0);}
168         if(vis_b[Cantor(tmp)]==-1){
169           vis_b[Cantor(tmp)]=tmp.g;
170           b.push(tmp);
171         }
172     }
173 }
174 
175 void double_BFS(){
176     int len1,len2;
177     f.push(Head);b.push(Tail);
178     vis_f[Cantor(Head)]=vis_b[Cantor(Tail)]=0;
179     while(!f.empty() || !b.empty()){
180         len1=f.size();len2=b.size();
181         if(len1>len2){
182             if(len2)expand_b();
183             expand_f();
184         }
185         else {
186             if(len1)expand_f();
187             expand_b();
188         }
189     }
190 }
191 
192 int main(){
193     init();
194     double_BFS();
195     return 0;
196 }

 

代码量比较大,竟然有个小200....

 

posted @ 2015-05-16 23:41  MedalPluS  阅读(502)  评论(0编辑  收藏  举报