2007百度之星总决赛试题八方块移动的简单算法

来源:互联网 发布:淘宝人群导购 编辑:程序博客网 时间:2024/05/01 17:56

 

八方块移动游戏要求从一个含8个数字(用1-8表示)的方块以及一个空格方块(用0表示)的3x3矩阵的起始状态开始,
不断移动该空格方块以使其和相邻的方块互换,直至达到所定义的目标状态。
空格方块在中间位置时有上、下、左、右4个方向可移动,在四个角落上有2个方向可移动,在其它位置上有3个方向可移动。
例如,假设一个3x3矩阵的初始状态为:

  8   0   3  
  2   1   4  
  7   6   5  

  要求的目标状态为:  
  1   2   3  
  8   0   4  
  7   6   5  

  则一个合法的移动路径为:  
  8   0   3           8   1   3          8   1   3          0   1   3         1   0   3         1   2   3  
  2   1   4   =>   2   0   4   =>   0   2   4   =>   8   2   4   => 8   2   4   => 8   0   4  
  7   6   5           7   6   5          7   6   5          7   6   5          7   6   5        7   6   5  

另外,在所用可能的从初始状态到目标状态的移动路径中,步数最少的路径被称为最短路径;
在上面的例子中,最短路径为5。如果不存在从初始状态到目标状态的任何路径,则称该组状态无解。   
 请设计算法找到从八方块的某初始状态到某目标状态的所有可能路径的最短路径

 

  1. #define WIN32_LEAN_AND_MEAN     
  2. #define _CRT_SECURE_NO_DEPRECATE
  3. #include <iostream>
  4. #include <map>
  5. #include <queue>
  6. #include <cstring>
  7. #include <ctime>
  8. #include <cassert>
  9. const unsigned int strLength = 9;
  10. using namespace std;
  11. // 交换字符串src中 x和y的值,返回被交换后的新串
  12. char* swap(char* src, int x, int y)
  13. {
  14.     assert(strlen(src)==strLength);
  15.     char* dest = new char[strLength+1];
  16.     strcpy(dest, src);
  17.     char temp = dest[x];
  18.     dest[x] = dest[y];
  19.     dest[y] = temp;
  20.     return dest;
  21. }
  22. //为Map<char*,char*>提供的比较函数.用于比较字符串值,取代默认的比较字符串地址
  23. struct ltstr
  24. {
  25.     bool operator()(const char* s1, const char* s2) const
  26.     {
  27.         return strcmp(s1, s2) < 0;
  28.     }
  29. };
  30. //核心算法,start为初始状态 goal为目标状态
  31. //没有使用A* 算法 或启发式寻找 我在这个题目中,我找不到这样的启发条件. 
  32. //我觉的启发式并不一定能得到最优解 这题明确要求是最短路径
  33. //用队来实现广度优先 用map来保存所有节点.实现图的效果 map中每项数据由<节点,节点的父节点>构成
  34. //返回值为两种状态需要的最短步数.
  35. int FindStep(char* start, char* goal)
  36. {
  37.     assert(strlen(start)==strLength);
  38.     assert(strlen(goal)==strLength);
  39.     map<char*, char*, ltstr> strMap;
  40.     map<char*, char*,ltstr>::iterator iter;
  41.     queue<char*> strQueue;
  42.     strQueue.push(start);
  43.     unsigned int step = 0;
  44.     while (!strQueue.empty())
  45.     {
  46.         char* str = strQueue.front();
  47.         strQueue.pop();
  48.         //确定节点中字符'0'所在的位置
  49.         unsigned int pos;
  50.         for (pos = 0; pos < strLength && str[pos] != '0'; pos++);
  51.         
  52.         //由当前结点移位得到4个新的子结点的指针数组初始为NULL
  53.         char* generate[4];
  54.         for (int i = 0; i < 4; i++)
  55.             generate[i] = NULL;
  56.         //当前节点左移 右移 上移 下移 并生成新节点 
  57.         if ((pos % 3) != 0) generate[0] = swap(str, pos, pos - 1);
  58.         if ((pos % 3) != 2) generate[1] = swap(str, pos, pos + 1);
  59.         if (pos > 2)        generate[2] = swap(str, pos, pos - 3);
  60.         if (pos < 6)        generate[3] = swap(str, pos, pos + 3);
  61.         //处理生成的四个新节点
  62.         for (int i = 0; i < 4; i++)
  63.         {
  64.             if (generate[i] == NULL)
  65.                 continue;
  66.             //如果此结点图中(Map中)已存在,删除此结点 并返回
  67.             if (strMap.find(generate[i]) != strMap.end())
  68.             {
  69.                 delete generate[i];
  70.                 continue;
  71.             }
  72.             //如果此结点不是目标状态节点则入队,并将此节点加入图中
  73.             if (strcmp(generate[i], goal) != 0)
  74.             {
  75.                 strQueue.push(generate[i]);
  76.                 strMap.insert(make_pair(generate[i], str));
  77.                 continue;
  78.             }
  79.             
  80.             strMap.insert(make_pair(generate[i], str));
  81.             char *back = generate[i];
  82.             
  83.             //执行到这里则说明此结点为目标状态结点遁环查找其父结点
  84.             while (strcmp(back, start) != 0)
  85.             {
  86.                 step++;
  87.                 back = (strMap.find(back))->second;
  88.                 cout << back << "/n";
  89.             }
  90.             //释放内存 并返回步数;
  91.             for (iter = strMap.begin(); iter != strMap.end(); iter++)
  92.                 delete iter->first;
  93.             return step;
  94.         }
  95.     }
  96.     //目标状态不可到达 释放内存 返回-1;
  97.     for (iter = strMap.begin(); iter != strMap.end(); iter++)
  98.         delete iter->first;     
  99.     return -1;
  100. }
  101. int main()
  102. {
  103.     //char* start = "803214765";
  104.     char* start = "784356102";
  105.     char* goal = "123804765";
  106.     //char* goal = "012345678";
  107.     cout << "开始寻找..." << endl;
  108.     clock_t  startTime = clock();
  109.     cout << "需要 " << FindStep(start, goal) << " 步.(如果为-1则目标状态不可到达) /n";
  110.     cout << "共用时" << (clock() - startTime) << "毫秒.(关闭FindStep函数中的cout输出可以更快点) "<<endl;
  111.     system("PAUSE");
  112.     return 0;
  113. }