问题描述:
有一个3×3的棋盘,其中有0~8九个数字,0表示空格,其他的数字可以和0交换位置。求由初始状态到达目标状态步数最少的解。
解决八数码问题的常用方法为图搜索法,可用广度优先、深度优先和A*算法实现,其中A*算法又因估价函数的不同而有着不同的搜索时间。
程序说明:
在本程序中,用A*算法分别实现了八数码问题,其中A*算法的估价函数选择的是“不在位”数和当前层数之和,初始状态和目标状态均可由用户设定,初始状态和目标状态由文件读入(test.txt):
初始状态:
2 8 3
1 6 4
7 0 5
目标状态:
1 2 3
8 0 4
7 6 5
程序的输出为:
程序为:
将程序改了下,使用了优先队列和哈希式查找,使在OPEN表找最小f值的时间缩小至NlogN,而且在扩展节点的时候判断节点是否已经扩展过的时间为o(1)了
输入:
输出:
程序是改出来的,没有一气呵成的感觉
Code
/*#include<iostream>
using namespace std;
static int primes[168] =
{2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997
};
int main()
{
long int a=22345680;
int i=0;
while (i<168)
{
if (a%primes[i]==0)
{
a=a/primes[i];
cout<<primes[i]<<endl;
}
else
i++;
}
system("pause");
}*/
#include<iostream>
using namespace std;
#include <vector>
#include <string>
#include <algorithm>
#include <fstream>
#include <map>
#include <sstream>
#include <ctime>
#include <queue>
int orignal[3][3]={0};//初始状态
int goal[3][3]={0};//目标状态
map<string,string> closed;//closed表
map<string,string> conn;//记录指针
map<string,int> value; //初始节点s到目标节点g的最短路径的耗散值的估计值的估计值
string sorignal;
string sgoal;
int (*g)(string);//计算初始节点s到中间节点n的最短路径的耗散值的估计值,本程序中用节点的深度表示
int (*h)(string);//计算中间节点n到目标节点g的最短路径的耗散值的估计值,本程序中用不在位数表示
int p(string);//使用距离数
int w(string);//“不在位”数
void init(ifstream &);//输入初始状态和目标状态
bool solve();//A*算法求解过程
void out(string,ofstream &);//输入初始状态到目标状态的步骤
void expand(string,string);//扩展节点
string transform(int mat[][3]);//辅助函数,将数组转化为字符串
void print(string,ofstream&);//辅助函数,输出矩阵
struct compare{ //比较函数
bool operator ()(const string &s1,const string &s2)
{
int a=value[s1];
int b=value[s2];
return a>b;
}
};
priority_queue<string,deque<string>,compare> open;//open表;
map<string,char> open2;//open表对应的hash表,用于查找;
string serve;//当前被扩展的节点
int main()
{
clock_t start, finish;
double duration;
start=clock();
ifstream in("test.txt");
ofstream ou("result.txt");
init(in);
if(solve())
{
string s=closed[serve];
out(s,ou);
printf("\n");
}
else
cout<<"unsolvable"<<endl;
finish=clock();
duration = (double)(finish - start);
printf( "%f seconds\n", duration/1000000 );
}
void init(ifstream &in)
{
for (int i=1;i<=3;i++)
for (int j=1;j<=3;j++)
in>>orignal[i-1][j-1];
sorignal=transform(orignal);
for (int i=1;i<=3;i++)
for (int j=1;j<=3;j++)
in>>goal[i-1][j-1];
sgoal=transform(goal);
}
int w(string s)
{
int val=0;
for (int i=0;i<9;i++)
if (s[i]!=sgoal[i])
val++;
return val;
}
int p(string s)
{
int val=0;
char m;
int pos,pos2;
for (int i=0;i<9;i++)
{
m=48+i;
pos=s.find(m);
pos2=sgoal.find(m);
val+=abs(pos%3-pos2%3)+abs(pos/3-pos2/3);
}
return val;
}
string transform(int mat[][3])
{
stringstream s;
string ss;
for (int i=0;i<3;i++)
for (int j=0;j<3;j++)
{
s<<mat[i][j];
}
s>>ss;
return ss;
}
bool solve()
{
bool result=false;
string temp;
int pos;
h=w;
open.push(sorignal);
value[sorignal]=h(sorignal);
while (1)
{
if (open.empty())
return false;
serve=open.top();
open.pop();
closed[serve]=serve;
if (serve==sgoal)
return true;
pos=serve.find('0');
if (pos>=3)
{
temp=serve;
swap(temp[pos-3],temp[pos]);
expand(serve,temp);
}
if (pos<6)
{
temp=serve;
swap(temp[pos+3],temp[pos]);
expand(serve,temp);
}
if (pos%3<2)
{
temp=serve;
swap(temp[pos+1],temp[pos]);
expand(serve,temp);
}
if (pos%3>0)
{
temp=serve;
swap(temp[pos-1],temp[pos]);
expand(serve,temp);
}
}
}
void expand(string serve,string temp)
{
int f=value[serve]+1-h(serve)+h(temp);
if (open2.find(temp)!=open2.end())
{
if (f<value[temp])
{
value[temp]=f;
conn[temp]=serve;
}
return;
}
if(closed[temp]==temp)
return;
value[temp]=f;
conn[temp]=serve;
open.push(temp);
open2[temp]='c';
}
void out(string s,ofstream &ou)
{
if (conn.find(s)!=conn.end())
out(conn[s],ou);
print(s,ou);
}
void print(string a,ofstream &ou)
{
static int status=1;
ou<<"Status "<<status++<<":"<<endl;
for (int i=1;i<=9;i++)
{
ou<<a[i-1]<<" ";
if (i%3==0)
{
ou<<endl;
}
}
ou<<endl;
}
这个程序在visual studio 2008 中运行还是有问题的,如果在g++编译器就没有问题,很复杂的都可以算出来
因为是只是写程序,对程序有所研究,对问题本身没有研究,应该还有很多可以优化的地方