2005年百度之星程序设计大赛试题总决赛题目
题目描述:
八方块移动游戏要求从一个含 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 。如果不存在从初试状态到目标状态的任何路径,则称该组状态无解。
请设计有效的(细节请见评分规则)算法找到从八方块的某初试状态到某目标状态的所有可能路径中的最短路径,并用 C/C++ 实现。
输入数据:
程序需读入已被命名为 start.txt 的初始状态和已被命名为 goal.txt 的目标状态,这两个文件都由 9 个数字组成( 0 表示空格, 1-8 表示 8 个数字方块),每行 3 个数字,数字之间用空格隔开。
输出数据:
如果输入数据有解,输出一个表示最短路径的非负的整数;如果输入数据无解,输出 -1 。
自测用例:
如果输入为: start.txt 和 goal.txt ,则产生的输出应为:
5
又例,如果用
7 8 4
3 5 6
1 0 2
替换 start.txt 中的内容,则产生的输出应为:
21
这道题的解法应该是很典型的A*算法,记得在人工智能那门课上听过。但是还是不会写,永远想不明白A*算法里面“评价函数”是怎么构建出来的。所以只好用非常简单的暴力解法。
暴力解法,广度优先搜索算法。用一个整数代表9宫格的状态,整数的每4位代表9宫格里面的8个方格(确定了8个方格,第九个方格就固定了),确定0的位置,然后进行替换的广度优先搜索。
由于9宫格的状态最多有9!种,因此搜索的长度最大为362880=9!这也是为什么声明一个这么长的数组路径的原因。
代码如下(也很暴力,还是有很多可以优化的,写的太暴力了):
#include <iostream> #include <fstream> #include <Windows.h> using namespace std; const int LSIZE = 362881; struct State { unsigned int squre; unsigned int first; int p; int step; }; State path[LSIZE]; int pl = 0; State goal; ifstream fin("start.txt"); ifstream gin("goal.txt"); ofstream fout("result.txt"); void read() { int tmp; //read start fin >> path[pl].first; path[pl].p = 9; for (int i=8; i >= 1; i --) { fin >> tmp; path[pl].squre = (path[pl].squre << 4) | tmp; if (tmp ==0) { path[pl].p = i; } }//end for i path[pl].step = 0; pl ++; //read goal for (int i=0; i <9; i ++) { gin >> tmp; goal.squre = (goal.squre << 4) | tmp; }//end for i } bool contain(unsigned int d) { for (int i=0; i< pl; i ++) { if (path[i].squre == d) { return true; } } return false; } void search() { for (int i=0; i < pl; i ++) { int ps = path[i].p; //往上移动 if ( ps== 9) { // 右移动 unsigned int tmp = path[i].squre >> 28; unsigned int d = (tmp << 28) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } if (!contain(d)) { path[pl].first = tmp; path[pl].p = 8; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //下移动 tmp = (path[i].squre<<8) >> 28; d= (tmp<<20) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } if (!contain(d)) { path[pl].first = tmp; path[pl].p = 6; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } }//end 9 else if (ps == 8) { //左移动 unsigned int tmp = path[i].first; unsigned int d = (tmp << 28) ^ path[i].squre; // if (d==goal.squre) { goal.step = path[i].step +1; return ; } if (!contain(d)) { path[pl].first = 0; path[pl].p = 9; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //右移动 tmp = (path[i].squre << 4) >> 28; d = (tmp<<28) ^ (tmp<<24) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 7; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //下移动 tmp = (path[i].squre << 12) >> 28; d = (tmp << 28 ) ^ (tmp<<16) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 5; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } } else if (ps == 7) { //右移动 unsigned int tmp = path[i].squre >> 28; unsigned int d = (tmp << 24) ^ (tmp << 28) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 8; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //下移动 tmp = (path[i].squre <<16) >>28 ; d = (tmp << 24) ^ (tmp << 12) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 4; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } } else if (ps == 6) { //上移动 unsigned int tmp =path[i].first; unsigned int d = (tmp << 20) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = 0; path[pl].p = 9; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //下移动 tmp = (path[i].squre << 20) >>28 ; d = (tmp << 20) ^ (tmp << 8) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 3; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //右移动 tmp = (path[i].squre << 12) >>28 ; d = (tmp << 20) ^ (tmp << 16) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 5; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } } else if(ps == 5) { //上移动 unsigned int tmp = path[i].squre >> 28; unsigned int d = (tmp << 16) ^ (tmp << 28) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 8; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //右移动 tmp = (path[i].squre << 16) >>28 ; d = (tmp << 16) ^ (tmp << 12) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 4; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //左移动 tmp = (path[i].squre << 8) >>28 ; d = (tmp << 20) ^ (tmp << 16) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 6; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //xia移动 tmp = (path[i].squre << 24) >>28 ; d = (tmp << 4) ^ (tmp << 16) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 2; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } } else if (ps == 4) { //上移动 unsigned int tmp = (path[i].squre <<4) >> 28; unsigned int d = (tmp << 12) ^ (tmp << 24) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 7; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //xia tmp = (path[i].squre << 28) >>28 ; d = (tmp) ^ (tmp << 12) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 1; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //zou tmp = (path[i].squre << 12) >>28 ; d = (tmp<<16) ^ (tmp << 12) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 5; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } } else if (ps == 3) { //上移动 unsigned int tmp = (path[i].squre <<12) >> 28; unsigned int d = (tmp << 8) ^ (tmp << 20) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p =6; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //右 tmp = (path[i].squre << 24) >>28 ; d = (tmp<<4) ^ (tmp << 8) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 2; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } } else if (ps == 2) { //上移动 unsigned int tmp = (path[i].squre <<12) >> 28; unsigned int d = (tmp << 16) ^ (tmp << 4) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p =5; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //zou tmp = (path[i].squre << 20) >>28 ; d = (tmp<<4) ^ (tmp << 8) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 3; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //you tmp = (path[i].squre << 28) >>28 ; d = (tmp) ^ (tmp << 4) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 1; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } } else if (ps == 1) { //shang unsigned int tmp = (path[i].squre <<16) >> 28; unsigned int d = (tmp << 12) ^ (tmp) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p =4; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } //zou tmp = (path[i].squre << 24) >>28 ; d = (tmp) ^ (tmp << 4) ^ path[i].squre; if (d==goal.squre) { goal.step = path[i].step +1; return ; } // if (!contain(d)) { path[pl].first = path[i].first; path[pl].p = 2; path[pl].squre =d; path[pl].step = path[i].step + 1; pl ++; } } } goal.step = -1; return; } int main() { long t_s = GetTickCount(); read(); search(); fout <<goal.step<<endl; long t_e = GetTickCount(); fout << "TIME:" << t_e - t_s << endl; return 0; }