问题描述:

       有一个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

程序的输出为:

 

Status 2:
2 8 3 
1 0 4 
7 6 5 

Status 
3:
2 0 3 
1 8 4 
7 6 5 

Status 
4:
0 2 3 
1 8 4 
7 6 5 

Status 
5:
1 2 3 
0 8 4 
7 6 5 

Status 
6:
1 2 3 
8 0 4 
7 6 5 

 程序为:

}

 

将程序改了下,使用了优先队列和哈希式查找,使在OPEN表找最小f值的时间缩小至NlogN,而且在扩展节点的时候判断节点是否已经扩展过的时间为o(1)了

输入:

0

输出:

 

Status 2:
6 4 7 
8 5 1 
3 2 0 

Status 
3:
6 4 7 
8 5 1 
3 0 2 

Status 
4:
6 4 7 
8 5 1 
0 3 2 

Status 
5:
6 4 7 
0 5 1 
8 3 2 

Status 
6:
6 4 7 
5 0 1 
8 3 2 

Status 
7:
6 4 7 
5 1 0 
8 3 2 

Status 
8:
6 4 7 
5 1 2 
8 3 0 

Status 
9:
6 4 7 
5 1 2 
8 0 3 

Status 
10:
6 4 7 
5 1 2 
0 8 3 

Status 
11:
6 4 7 
0 1 2 
5 8 3 

Status 
12:
6 4 7 
1 0 2 
5 8 3 

Status 
13:
6 0 7 
1 4 2 
5 8 3 

Status 
14:
6 7 0 
1 4 2 
5 8 3 

Status 
15:
6 7 2 
1 4 0 
5 8 3 

Status 
16:
6 7 2 
1 0 4 
5 8 3 

Status 
17:
6 0 2 
1 7 4 
5 8 3 

Status 
18:
0 6 2 
1 7 4 
5 8 3 

Status 
19:
1 6 2 
0 7 4 
5 8 3 

Status 
20:
1 6 2 
7 0 4 
5 8 3 

Status 
21:
1 6 2 
7 4 0 
5 8 3 

Status 
22:
1 6 2 
7 4 3 
5 8 0 

Status 
23:
1 6 2 
7 4 3 
5 0 8 

Status 
24:
1 6 2 
7 4 3 
0 5 8 

Status 
25:
1 6 2 
0 4 3 
7 5 8 

Status 
26:
1 6 2 
4 0 3 
7 5 8 

Status 
27:
1 0 2 
4 6 3 
7 5 8 

Status 
28:
1 2 0 
4 6 3 
7 5 8 

Status 
29:
1 2 3 
4 6 0 
7 5 8 

Status 
30:
1 2 3 
4 0 6 
7 5 8 

Status 
31:
1 2 3 
4 5 6 
7 0 8 

Status 
32:
1 2 3 
4 5 6 
7 8 0 

 程序是改出来的,没有一气呵成的感觉

 #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++编译器就没有问题,很复杂的都可以算出来

 因为是只是写程序,对程序有所研究,对问题本身没有研究,应该还有很多可以优化的地方

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-02-07
  • 2021-08-02
  • 2022-03-01
猜你喜欢
  • 2022-02-03
  • 2021-07-21
  • 2021-10-29
相关资源
相似解决方案