3*3拼图还原问题(启发式搜索)

蹲街弑〆低调 提交于 2020-02-05 12:26:43

问题与程序参考《挑战程序设计竞赛》19.2 ALDS1_13_B:8 Puzzle

 

 

  1 /*
  2 3*3拼图用的是广度优先搜索
  3 编程核心关键词是这么几个
  4 队列queue 拼图数据结构puzzle 状态记录数组V  方向数组dx,dy 、
  5 开始会看这算法,可能会被吓着,觉得好难,但实际上理解一番,、
  6 就会发现这个算法实际上就是模拟我们拼图,但与我们拼图不太一样的
  7 是:
  8 1.它会记住所有自己试探的失败情况(状态记录数组V); 
  9 2.它会按照“规则”一个个来试探,而不像我们人一样,按照自己的感觉与大致推断来进行试探;
 10 [当然,这种人具有的感觉性的“预判”也是能在算法里量化大概模拟下的,也就是进行“剪枝”操作,
 11 涉及IDA*(迭代加深A*)、A*] 
 12 
 13 编程方面的话,开始时候创建一个自定义数据类型Puzzle,里面包含
 14 f[N2]  对应某阶段的拼图
 15 space  空格所处位置的下标
 16 path   记录移动的方法
 17 以及<的运算符重载
 18 
 19 利用广度优先搜索,弹出队列首部的Puzzle,
 20 在预先的“是否找寻到最终目标”的judge函数判断后开始进行"试探”,
 21 利用Puzzle.space与行下标x,列下标y的对应关系,
 22 x=u.space/3;        //行下标 
 23 y=u.space%3;        //列下标 
 24 生成空白块的在二维数组f的位置信息
 25 随后,利用for循环、dx、dy、空白块位置,进行"符合规则”的试探,
 26 并将新生成的Puzzle放入队列queue之中
 27 在经过多次试探后,如果有答案,会输出答案,但如果没有答案,即
 28 "队列为空",就输出“unsolvable” 
 29 
 30 博客里放了张图,这是为了更快理清"输入样例1"的处理过程而画的 
 31 */
 32 #include<iostream>
 33 #include<cmath>
 34 #include<string>
 35 #include<map>
 36 #include<queue>
 37 using namespace std;
 38 #define N 3
 39 #define N2 9 
 40 static const int dx[4]={-1,0,1,0};
 41 static const int dy[4]={0,-1,0,1};
 42 static const char dir[4]={'u','l','d','r'};
 43 struct Puzzle{
 44     int f[N2];
 45     int space;
 46     string path;
 47     bool operator < (const Puzzle &p)const{
 48         for(int i=0;i<N2;i++){
 49             if(f[i]==p.f[i]) continue;
 50             return f[i]>p.f[i]; 
 51         }
 52         return false;
 53     }
 54 }; 
 55 bool judge(Puzzle p){
 56     for(int i=0;i<N2;i++){
 57         if(p.f[i]!=(i+1))
 58         return false;
 59     }
 60     return true;
 61 } 
 62 void showpic(Puzzle s){
 63     cout<<"path:"<<s.path; 
 64     for(int i=0;i<N2;i++){
 65         if(!(i%3)) cout<<endl;
 66         if(s.f[i]!=9)
 67         cout<<s.f[i]<<" ";
 68         else
 69         cout<<"0 "; 
 70     }
 71     cout<<endl;
 72 }
 73 string bfs(Puzzle s){
 74     queue<Puzzle> Q;
 75     map<Puzzle,bool> V;//记录是否已经使用过 
 76     Puzzle u,v; 
 77     s.path="";//空白字符串 
 78     Q.push(s);//入队列 
 79     V[s]=true;
 80     while(!Q.empty()){
 81         u=Q.front();
 82         Q.pop();
 83         //showpic(u);//显示当前移动情况 
 84         if(judge(u)) return u.path;
 85         int sx=u.space/N;
 86         int sy=u.space%N;
 87         for(int r=0;r<4;r++){
 88             int tx=sx+dx[r];
 89             int ty=sy+dy[r];
 90             if(tx<0||ty<0||tx>=N||ty>=N) continue;
 91             v=u;
 92             swap(v.f[u.space],v.f[tx*N+ty]);
 93             v.space=tx*N+ty;
 94             if(!V[v]){
 95                 
 96                 V[v]=true;//访问标记 
 97                 v.path+=dir[r];
 98                 Q.push(v);
 99             } 
100         }
101          
102     } 
103     
104     return "unsolvable";
105      
106 }
107 int main(){
108     Puzzle in;
109     for(int i=0;i<N2;i ++){
110         cin>>in.f[i]; 
111     if(in.f[i]==0){
112         in.f[i]=N2;
113         in.space=i; 
114         }
115     }
116     string ans=bfs(in);
117     cout<<"answer:"<<ans<<endl; 
118     cout<<ans.size()<<endl;//最终的结果 
119 } 
120 /*样例输入1 
121 1 3 0
122 4 2 5
123 7 8 6
124   样例输出1
125 answer:ldrd
126 4
127 */
128 /*样例输入2
129 1 2 3
130 4 5 6
131 8 7 0
132 样例输出2
133 answer:unsolvable
134 10
135 */
136  

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!