八数码问题:C++广度搜索实现

毕竟新手上路23333,有谬误还请指正。 课程设计遇到八数码问题(这也是一坨),也查过一些资料并不喜欢用类函数写感觉这样规模小些的问题没有必要,一开始用深度搜索却发现深搜会陷入无底洞,如果设定了深度限制又会有很多情况无法找到,然后果断放弃,改用广度搜索。  如果要改善代码效率还可以用双向搜索,即从起始状态和最终状态同时搜索,找到相同状态,这样搜索时间会缩短一半。此外还可以用A*(启发式算法)会显得高端很多。

题目要求: 在一个3*3的棋盘上,随机放置1到8的数字棋子,剩下一个空位。数字可以移动到空位(编程时,空位可用0代替,且可以理解为是空位的上、下、左、右移动),经过若干次移动后,棋局到达指定目标状态。 数组表示棋局状态。用函数表示空格(0)的移动,使用函数具有前提条件,满足条件才可以使用。 用广度优先或深度优先搜索求解。还可以使用启发式求解,以提高搜索效率。 要求: ① 编程求解问题; ② 给出中间状态; ③ 给出解序列(函数调用序列)

  1 #include <iostream>
  2 #include <vector>
  3 #include <string>
  4 #include <queue>
  5 #include <algorithm>
  6 #include <cmath>
  7 #include <ctime>
  8 #include <cstdio>
  9 #include <sstream>
 10 #include <deque>
 11 #include <functional>
 12 #include <iterator>
 13 #include <list>
 14 #include <map>
 15 #include <memory>
 16 #include <stack>
 17 #include <set>
 18 #include <numeric>
 19 #include <utility>
 20 #include <cstring>
 21 #include <fstream>
 22
 23 using namespace std;
 24 int board[25];                //初始状态,一维数组模拟二维
 25 int destboard[25];            //目标状态
 26 int dx[] = {-1, 0, 1, 0};     //数字0的移动偏移量
 27 int dy[] = {0, 1, 0, -1};
 28 map<int, bool> mark;          //记录已搜索的状态
 29
 30 int lists(int i, int j)
 31 {
 32     return i*5 + j;          //返回i, j二维数组的一维位置
 33 }
 34
 35 int judge()                  //运算前判断是否可以找到一种对于初末状态可行的变换
 36 {
 37     int first_d[10],last_d[10],i,j=6,k,rank1=0,rank2=0;
 38     for(i=1;i<=9;i++)        //初状态赋值给first_d[10]
 39     {
 40         while(1)
 41         {
 42             if(j==9){j=11;}
 43             if(j==14){j=16;}
 44             first_d[i]=destboard[j];
 45             j++;
 46             break;
 47         }
 48     }
 49     j=1;i=1;
 50     for(k=1;k<=9;k++)        //最终状态赋值给last_d[10]
 51     {
 52         while(1)
 53         {
 54             last_d[k]=board[lists(i, j)];
 55             j++;
 56             if(j==4){i++;j=1;}
 57             break;
 58         }
 59     }
 60
 61     for(j=2;j<=9;j++)        //计算初状态的奇偶性
 62     {
 63         for(i=1;i<j;i++)
 64         {
 65           if(first_d[i]>first_d[j]&&first_d[i]!=0&&first_d[j]!=0){rank1++;}
 66         }
 67     }
 68
 69     for(j=2;j<=9;j++)       //计算末状态的奇偶性
 70     {
 71         for(i=1;i<j;i++)
 72         {
 73             if(last_d[i]>last_d[j]&&last_d[i]!=0&&last_d[j]!=0){rank2++;}
 74         }
 75     }
 76     int a1=rank1%2,a2=rank2%2;
 77     if(a1!=a2){return 0;}  //判断奇偶性是否相同,相同才可以从出状态变到末状态
 78     else{return 1;}
 79 }
 80
 81 struct Stat               //结构体三个参数
 82 {
 83     int step;             // 步数
 84     int board[25];        // 状态
 85     Stat(int *b, int s=0)
 86     {
 87     memcpy(this->board, b, sizeof(int)*25); //对状态的赋值操作
 88     step = s;
 89     }
 90 };
 91
 92 bool ok(int *b)          // 判断是否到已经达目标状态
 93 {
 94     for(int i=1; i<=3; ++i)
 95     for(int j=1; j<=3; ++j)
 96     {
 97         if(b[lists(i, j)] != destboard[lists(i, j)])
 98         return false;
 99     }
100     return true;
101 }
102
103 int Bfs()
104 {
105     int judge_first=judge();
106     ofstream ofs;                   //建立数据外存文件
107     ofs.open("output.dat");
108     if(judge_first==0){cout<<"不存在"<<endl;return 2333333;}
109     if(judge_first==1)
110     {
111         queue<Stat> que;            //建队que
112         que.push(Stat(board, 0));   // 初始状态入队
113         while(que.size())
114         {
115             int m=0, mk=1;          // 记录状态m,以及基数mk
116             Stat p = que.front();   //取出队头元素
117             for(int i=1; i<=3; ++i)
118             {
119                 for(int j=1; j<=3; ++j)
120                 {
121                     ofs<<p.board[lists(i, j)]<<" ";
122                 }
123                 ofs<<endl;
124             }
125             ofs<<endl;
126
127             que.pop();              //出队
128
129             if(ok(p.board))
130             {
131                 return p.step;      // 到达目标则返回最短步数
132             }
133
134             for(int i=1; i<=3; ++i)  // 这个是为了标记初始状态,不能遗漏
135             for(int j=1; j<=3; ++j)
136             {
137                 m+=p.board[lists(i, j)]*mk;
138                 mk*=10;
139             }
140             if(!mark.count(m))             // 未标记则标记
141             mark[m] = true;
142
143             for(int k=0; k<4; ++k)         // 四个方向搜索
144             {
145                 Stat n(p.board, p.step+1); // n是下一步搜索的状态
146                 int zx, zy;                // zx,zy存放当前状态0的位置
147
148                 for(int i=1; i<=3; ++i)    // 搜索当前状态的0的位置
149                 for(int j=1; j<=3; ++j)
150                 {
151                     if(p.board[lists(i,j)]==0)
152                     {
153                         zx = i;
154                         zy = j;
155                         break;
156                     }
157                     if(p.board[lists(i,j)]==0)
158                     break;
159                 }
160
161                 int nx = zx+dx[k];      //下一个状态的0的位置
162                 int ny = zy+dy[k];
163                 m = 0;                  //标记状态
164                 mk = 1;
165                 swap(n.board[lists(nx,ny)],n.board[lists(zx, zy)]);  //交换
166
167                 for(int i=1; i<=3; ++i)
168                 for(int j=1; j<=3; ++j)
169                 {
170                     m+=n.board[lists(i, j)]*mk;
171                     mk*=10;
172                 }
173                 if(!mark.count(m))
174                 {
175                     mark[m] = true;
176                     que.push(n);           //若未搜索过,则入队
177                 }
178             }
179         }
180         ofs.close();                       //结束外存
181         return 2333333;
182     }
183     return 0;
184 }
185
186 int main()
187 {
188     cout<<"广度搜索八数码问题:\n";
189     cout<<"请输入初始状态用0-8表示\n";
190     memset(board, 0, sizeof(board));
191     for(int i=1; i<=3; ++i)
192     for(int j=1; j<=3; ++j)
193     scanf("%1d", &board[lists(i, j)]);
194
195     cout<<"请输入结束状态\n";
196     for(int m=6;m<=8;m++){scanf("%d",&destboard[m]);}
197     for(int m=11;m<=13;m++){scanf("%d",&destboard[m]);}
198     for(int m=16;m<=18;m++){scanf("%d",&destboard[m]);}
199     mark.clear();
200
201     cout<<"准备搜索...\n";
202     system("pause");
203     cout<<"搜索中.....\n";
204
205     int t=Bfs();
206     cout<<"搜索完毕,过程已经以文件的形式存储\n";
207     if(t==2333333){cout<<"没有找到"<<endl;}
208     else{cout<<"深度为:"<<t<< endl;}
209     system("pause");
210     return 0;
211 }

输入初始状态和最终状态,中间过程会生成在”output.dat”中。

时间: 2024-11-03 21:41:13

八数码问题:C++广度搜索实现的相关文章

八数码问题——双向广度优先搜索解决

八数码问题:在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所示,要求对空格执行空格左移.空格右移.空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态. 搜索顺序有两种: (1)两个方向交替进行扩展 (2)每次选择节点少的那个扩展 一般来说方法(2)可以克服两端生长不平衡的现象 // eight.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<vector> #include&l

HDU 1043 八数码(A*搜索)

在学习八数码A*搜索问题的时候需要知道以下几个点: Hash:利用康托展开进行hash 康托展开主要就是根据一个序列求这个序列是第几大的序列. A*搜索:这里的启发函数就用两点之间的曼哈顿距离进行计算就可以. 减枝:在八数码里,任意交换一个空行和一个位置的数字,这个八数码的逆序数是不变的,这样就可以根据目前状态判断是否可达终点状态了. 第一次做这个题用的map进行哈希,结果果断超时,之后又写了LRJ书上的hash方法也超时了,最后只能用康托展开了 详细请参考:[八数码的八重境界] http://

codevs1225八数码难题(搜索&#183;)

1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.问题描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最

搜索进阶1、八数码(HDU1043)

http://acm.hdu.edu.cn/showproblem.php?pid=1043 八数码八境界: https://www.cnblogs.com/zufezzt/p/5659276.html 借用了MAP哈希,发现只能过hdu(249ms),poj一直TLE. 还是先上个代码吧,以后再改用康拓展开来哈希.. 1 #include<stdio.h> 2 #include<algorithm> 3 #include<string.h> 4 #include<

广度优先搜索解决八数码问题

八数码简介 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每一个棋子上标有1至8的某一数字,不同棋子上标的数字不同样.棋盘上另一个空格,与空格相邻的棋子能够移到空格中.要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤.所谓问题的一个状态就是棋子在棋盘上的一种摆法.棋子移动后,状态就会发生改变.解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态. 求解八数码问题要懂得的知识 1.康托展开,八数码在交换的过程

八数码

八数码问题 一.问题描述 所谓八数码问题是指:将分别标有数字1,2,3,…,8的八块正方形数码牌任意地放在一块3×3的数码盘上.放牌时要求不能重叠.于是,在3×3的数码盘上出现了一个空格.现在要求按照每次只能将与空格相邻的数码牌与空格交换的原则,将任意摆放的数码盘逐步摆成某种特殊的排列. 二.问题分析 首先,八数码问题包括一个初始状态(strat) 和 目标状态(goal),所谓解八数码问题就是在两个状态间寻找一系列可过渡状态(strat-> strat 1-> strat 2->...

HDU 1043 Eight八数码解题思路(bfs+hash 打表 IDA* 等)

题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原为初始状态 思路: 参加网站比赛时拿到此题目,因为之前写过八数码问题,心中暗喜,于是写出一套暴力bfs+hash,结果TLE呵呵 思路一:bfs+hash(TLE) 1 #include <cstdio> 2 #include <cstring> 3 #include <queu

八数码的八境界 [转载]

八数码的八境界   研究经典问题,空说不好,我们拿出一个实际的题目来演绎.八数码问题在北大在线测评系统中有一个对应的题,题目描述如下: Eight Time Limit: 1000MS    Memory Limit: 65536K  Special Judge Description The 15-puzzle has been aroundfor over 100 years; even if you don't know it by that name, you've seen it. I

【转】八数码问题及A*算法

一.八数码问题八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个空格,与空格相邻的棋子可以移到空格中.要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤.所谓问题的一个状态就是棋子在棋盘上的一种摆法.棋子移动后,状态就会发生改变.解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态.八数码问题一般使用搜索法来解.搜索法有广度优先搜索法.深度优