洛谷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....
时间: 2024-11-24 04:46:22