移动拼图游戏(八数码问题) BFS版
来源:互联网 发布:读书app 知乎 编辑:程序博客网 时间:2024/06/05 07:27
小时候玩过的移动拼图游戏。有一个3*3的棋盘,其中有0-8这9个数字,0表示空格,每次移动只能把空格旁边的数字移到空格,即与0相邻的数字可以和0交换位置。
求从初始状态
2 3 0
7 1 6
5 8 4
变到目标状态
1 2 3
4 5 6
7 8 0
的最佳移动方案。
今天先用BFS练练手。
每个结点用一个长度为9的数组记录当前矩阵;用blankPos变量记录空格位置,便于计算出相邻结点;用parent指针指向BFS过程中的父节点,用于找到目标时回溯出路径。
起始结点先入队,用set将其标记为访问过。每次从队列中取出一个结点,计算出其相邻结点(可能是2个、3个、4个),若其相邻结点未访问过,则入队,并用set将其标记为访问过。
/*2015.8.3cyq*///八数码BFS#include <iostream>#include <vector>#include <queue>#include <set>#include <time.h>using namespace std;struct Node{vector<int> data;int blankPos;//空格(用0表示)位置,用于计算出相邻结点Node *parent;};//检测结点是否相等bool isEqual(Node *&a,Node *&b){for(int i=0;i<9;i++)if(a->data[i]!=b->data[i])return false;return true;}//检测是否有解bool canSolve(Node *&a,Node *&b){int sum1=0,sum2=0;for(int i=0;i<9;i++)for(int j=i+1;j<9;j++){if(a->data[i] > a->data[j]&&a->data[j]!=0)sum1++;if(b->data[i] > b->data[j]&&b->data[j]!=0)sum2++;}return (sum1%2==sum2%2);//奇偶性相同才有解}//显示结点的数据矩阵void Show(Node *&a){if(a==nullptr)return;for(int i=0;i<9;i++){if(a->data[i]==0)cout<<" ";else cout<<a->data[i]<<" ";if((i+1)%3==0)cout<<endl;}}//空格上移后的结点Node* upNode(Node *&a){if(a->blankPos<=2)return nullptr;else{Node* tmp=new Node(*a);swap(tmp->data[tmp->blankPos],tmp->data[tmp->blankPos-3]);tmp->blankPos-=3;return tmp;}}//空格下移后的结点Node* downNode(Node *&a){if(a->blankPos>=6)return nullptr;else{Node* tmp=new Node(*a);swap(tmp->data[tmp->blankPos],tmp->data[tmp->blankPos+3]);tmp->blankPos+=3;return tmp;}}//空格左移后的结点Node* leftNode(Node *&a){if(a->blankPos%3==0)return nullptr;else{Node* tmp=new Node(*a);swap(tmp->data[tmp->blankPos],tmp->data[tmp->blankPos-1]);tmp->blankPos--;return tmp;}}//空格右移后的结点Node* rightNode(Node *&a){if(a->blankPos%3==2)return nullptr;else{Node* tmp=new Node(*a);swap(tmp->data[tmp->blankPos],tmp->data[tmp->blankPos+1]);tmp->blankPos++;return tmp;}}int main(){clock_t time1,time2;//用于计算程序运行时间time1=clock();int ivec1[10]={2,3,0, 7,1,6, 5,8,4};//起始结点//int ivec1[10]={0,8,7,// 6,5,4,// 3,2,1};//起始结点int ivec2[10]={1,2,3, 4,5,6, 7,8,0};//目标结点Node a,b;for(int i=0;i<9;i++){//9代表空字符a.data.push_back(ivec1[i]);b.data.push_back(ivec2[i]);}for(int i=0;i<9;i++){if(a.data[i]==0)a.blankPos=i;if(b.data[i]==0)b.blankPos=i;}a.parent=nullptr;b.parent=nullptr;Node* startNode=&a;Node* targetNode=&b;if(!canSolve(startNode,targetNode)){cout<<"Can't solve!"<<endl;return 0;}queue<Node*> q;q.push(startNode);set<vector<int> > visited;visited.insert(startNode->data);while(!q.empty()){Node* root=q.front();q.pop();if(isEqual(root,targetNode)){targetNode->parent=root->parent;break;}Node* node1=upNode(root);Node* node2=downNode(root);Node* node3=leftNode(root);Node* node4=rightNode(root);if(node1!=nullptr&&visited.find(node1->data)==visited.end()){node1->parent=root;visited.insert(node1->data);q.push(node1);}if(node2!=nullptr&&visited.find(node2->data)==visited.end()){node2->parent=root;visited.insert(node2->data);q.push(node2);}if(node3!=nullptr&&visited.find(node3->data)==visited.end()){node3->parent=root;visited.insert(node3->data);q.push(node3);}if(node4!=nullptr&&visited.find(node4->data)==visited.end()){node4->parent=root;visited.insert(node4->data);q.push(node4);}}//利用结点的parent指针回溯出路径Node* p=targetNode;vector<Node*> result;while(p!=nullptr){result.push_back(p);p=p->parent;}int count=0;for(int i=result.size()-1;i>=0;i--){cout<<"stage:"<<count++<<endl;Show(result[i]);}time2=clock();cout<<"程序运行耗费的毫秒数:"<<(time2-time1)<<endl;return 0;}
测试后发现,从初始状态
2 3 0
7 1 6
5 8 4
变到目标状态
1 2 3
4 5 6
7 8 0
我的程序用2秒钟可以输出具体步骤,经历14次变换。
而从初始状态
0 8 7
6 5 4
3 2 1
变到目标状态
1 2 3
4 5 6
7 8 0
两个状态差距较大。需要137秒才能输出结果,经历28次变换。可见BFS层数大了之后,性能变得很差。
0 1
- 移动拼图游戏(八数码问题) BFS版
- 移动拼图游戏(八数码问题)A*版
- python 处理八数码 双向BFS 拼图游戏
- 八数码问题 bfs
- 八数码问题 BFS
- 八数码问题(bfs+哈希)
- 八数码问题 (stl bfs)
- 简单的八数码问题(BFS)
- 八数码问题(hash+bfs)
- 八数码(BFS)
- 八数码问题 bfs+map
- 八数码问题 BFS+hash
- 八数码问题 【隐式图bfs】
- 八数码问题详解(用bfs实现)
- UVA 10085(bfs+康拓展开)八数码问题
- 八数码问题bfs暴力破解(java实现)
- POJ 1077八数码问题(cantor展开+BFS)
- POJ 1077 Eight(bfs八数码问题)
- 黑马程序员-ios学习笔记 Foundation 中的 NSArray
- win10 下安装Genymotion模拟器打开出错解决方法...
- hive安装备注
- Android Binder 分析——多线程支持
- 图形绘制系统的体系结构总结
- 移动拼图游戏(八数码问题) BFS版
- Java之适配器模式(Adapter Pattern)
- Scala入门到精通——第十七节 类型参数(一)
- Ultra-QuickSort(POJ 2299)
- Potplayer
- 关于Servlet一点,做个简单的emp页面(1)
- java特殊运算符
- android广播和短信广播详解----使用广播接收者监听短信
- 1、C语言和设计模式(之开篇)