#include <bits/stdc++.h>
#include <string>
#include <map>
#define len 3
using namespace std;
struct node {
int a[3][3]; //九宫格
node* p; //指向当前节点的父节点
node* next; //指向队列中下一个节点
node(string s) {
for(int i=0;i<len;i++) {
for(int j=0;j<len;j++) a[i][j] = s[i*len+j]-'0';
}
p = NULL;
next = NULL;
}
node():p(NULL), next(NULL) {}
};
void input(node& start, node& target);
bool haveSolution(node start, node target);
string deCode(node t);
bool explore(node cur, node& ex, char dic);
node* getSolution(node* start, node* target);
void print(node* t);
int main() {
node start, target;
input(start, target);
if(!haveSolution(start, target)) {
cout<<"奇偶不同,无解!!!"<<endl;
return 0;
}
node* t = getSolution(&start, &target);
if(t == NULL) cout<<"无解!!!"<<endl;
else print(t);
system("pause");
return 0;
}
void input(node& start, node& target) {
//输入任意合法的初始状态和目标状态
cout<<"请输入八数码初始状态,以3*3矩阵形式输入,空格用0表示"<<endl;
for(int i=0;i<len;i++) {
for(int j=0;j<len;j++) cin>>start.a[i][j];
}
cout<<"请输入八数码目标状态,要求同初始状态"<<endl;
for(int i=0;i<len;i++) {
for(int j=0;j<len;j++) cin>>target.a[i][j];
}
}
bool haveSolution(node start, node target) {
//判断初始状态和目标状态是否同为奇排列或同为偶排列,即是否有解
string s = "", t = "";
int sc = 0, tc = 0;
for(int i=0;i<len;i++) {
for(int j=0;j<len;j++) {
s += start.a[i][j]+'0';
t += target.a[i][j]+'0';
}
}
for(int i=1;i<s.length();i++) {
for(int j=0;j<i;j++) {
if(s[j]<s[i] && s[i]!='0' && s[j]!='0') sc++;
if(t[j]<t[i] && t[i]!='0' && t[j]!='0') tc++;
}
}
if(sc%2 == tc%2) return true;
else return false;
}
string deCode(node t) {
//将九宫格中的数字编码为字符串
string r = "";
for(int i=0;i<len;i++) {
for(int j=0;j<len;j++) r += t.a[i][j]+'0';
}
return r;
}
bool explore(node cur, node& ex, char dic) {
//对当前状态cur进行扩展,dic为'u'表示空格向上移,'d'表示空格向下移
//'l'表示向左移,'r'表示向右移,若无法扩展,返回false,若扩展成功,返回true,
//并通过ex参数返回扩展后的节点
int r = 0, c = 0;
for(int i=0;i<len;i++) {
for(int j=0;j<len;j++) {
if(cur.a[i][j] == 0) {
r = i;
c = j;
break;
}
}
}
if(dic == 'u') {
if(r == 0) return false;
else swap(ex.a[r][c], ex.a[r-1][c]);
}
else if(dic == 'd') {
if(r == len-1) return false;
else swap(ex.a[r][c], ex.a[r+1][c]);
}
else if(dic == 'l') {
if(c == 0) return false;
else swap(ex.a[r][c], ex.a[r][c-1]);
}
else {
if(c == len-1) return false;
else swap(ex.a[r][c], ex.a[r][c+1]);
}
return true;
}
node* getSolution(node* start, node* target) {
map<string,bool> m;
node *front = start, *rear = front;
string tarCode = deCode(*target);
while(front!=NULL) {
string curCode = deCode(*front);
if(curCode == tarCode) {
//找到目标状态
return front;
}
else {
if(m.find(curCode)==m.end()) {
//当前状态还未扩展过,进行扩展
m[curCode] = true;
node* dic[4];
char op[4] = {'u','d','l','r'};
for(int i=0;i<4;i++) dic[i] = new node(curCode);
for(int i=0;i<4;i++) {
if(explore(*front, *dic[i], op[i])) {
dic[i]->p = front;
rear->next = dic[i];
rear = rear->next;
}
}
}
}
front = front->next;
}
return NULL;
}
void print(node* t) {
int count = 0;//转化次数
stack<node> s;
while(t!=NULL) {
s.push(*t);
t = t->p;
}
cout<<endl<<"转化路线"<<endl;
while(!s.empty()) {
node cur = s.top();
s.pop();
for(int i=0;i<len;i++) {
for(int j=0;j<len;j++) cout<<cur.a[i][j]<<" ";
cout<<endl;
}
cout<<endl;
count ++;
}
cout<<"转化次数:"<<count-1<<endl;
}
状态空间法求解八数码c++代码
最新推荐文章于 2021-05-19 06:09:00 发布