描述
国际象棋棋盘上有3个骑士,能否通过若干次移动走到一起。要选择一个位置汇合,使得3个骑士行动的总次数最少?
输入
第1行:1个正整数t,表示数据组数,2≤t≤10。
第2..t+1行:用空格隔开的3个坐标, 每个坐标由2个字符AB组成,A为'A'~'H'的大写字母,B为'1'~'8'的数字,表示3个棋子的初始位置。
输出
第1..t行:每行1个数字,第i行表示第i组数据中3个棋子移动到同一格的最小行动步数。
2 A1 A1 A1 B2 D3 F4
样例输出
0 2
解法一:搜索三个位置到所有位置的最小步数,再枚举所有位置,统计三个步数的和,求最小值。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <queue> using namespace std; char start[3][3];//表示三个骑士起始位置坐标字符表示 int step[3][8][8];//表示第i个骑士移动到(x,y)的最少步数 queue<pair<int, int>> q;//用于广度搜索的队列 int now_x, now_y; int next_x, next_y; int next_step[8][2] = {{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1}}; pair<int, int> move(int x, int y, int i) { x += next_step[i][0]; y += next_step[i][1]; return make_pair(x, y); } bool checkIsInChessboard(int x, int y) { if ((x >= 0 && x <= 7) && (y >= 0 && y <= 7)) return true; return false; } void bfs_solve(int s[][8] ,int x, int y) { //memset(s,-1,sizeof(s)); //初始化为-1,表示没有访问过,但是有问题,赋值为0,结果减1 //memset(s, 0, sizeof(s));为用这个就啥不行啊。。。 for (int i = 0; i < 8; ++i) for (int j = 0; j < 8; ++j) s[i][j] = -1; //清空队列 while (!q.empty()) q.pop(); s[x][y] = 0;//起始点,记为1 q.push(make_pair(x,y)); while (!(q.empty())) { //出队列 pair<int, int> tp = q.front(); now_x = tp.first; now_y = tp.second ; q.pop(); for (int i = 0; i < 8; ++i) { pair<int, int> tp = move(now_x, now_y, i); next_x = tp.first; next_y = tp.second; if (checkIsInChessboard(next_x, next_y) && s[next_x][next_y] == -1) { s[next_x][next_y] = s[now_x][now_y] + 1; q.push(make_pair(next_x, next_y)); } } } } int sumOfStep(int i, int j) { int k; int sum = 0; for (k = 0; k < 3; ++k) { sum += step[k][i][j]; } return sum; } int solve() { int i, j; for (i = 0; i < 3; ++i) { bfs_solve(step[i],start[i][0]-'A',start[i][1]-'1'); } int ans = 0x7FFFFFFF;//INFINITY; for (i = 0; i < 8; ++i) for (j = 0; j < 8; ++j) { int sum = sumOfStep(i, j); if (ans > sum) { ans = sum; } } return ans; } int main() { int t; cin >> t; while (t--) { cin >> start[0] >> start[1] >> start[2]; cout << solve() << endl; } return 0; }
解法二:将开始输入的三个位置转换为一个八进制数,作为一种初始状态,枚举三个位置加八个方向,共8^6个状态,若出现第一个符合条件的即为最小结果,已经通过了,开始move函数写的有问题,其实状态的改变是根据坐标来的,虽然值在正常范围内,坐标还是会出界,所以要改成判断坐标的方式来检查是否合法。还有就是checkOK方法写错了,忘了加两边的括号,导致总是返回false。
<pre name="code" class="cpp">#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <queue> using namespace std; char start[3][3];//表示三个骑士起始位置坐标字符表示 queue<int> q;//用于广度搜索的队列 int step[270000];//记录8^6个状态整数 int now_status;//将当前位置坐标映射成一个八进制数1-8 => 0-7,A-H => 0-7 int next_status; int next_step[8][2] = { { -2,1 },{ -1,2 },{ 1,2 },{ 2,1 },{ 2,-1 },{ 1,-2 },{ -1,-2 },{ -2,-1 } }; //将当前状态转移 //i表示第几个位置,j表示移动方向 //同时检查状态是否合法 int move(int status,int i, int j) { int now_site = (status >> (6 * (2 - i))) & 0x3F; int now_x = now_site >> 3; int now_y = now_site & 0x7; int next_site = now_site; int next_x = now_x - next_step[j][1]; int next_y = now_y + next_step[j][0]; //if (next_site >= 0 && next_site <= 0x3F) //next_status = status - (now_site << (6 * (2 - i))) + (next_site << (6 * (2 - i)));//修改对应位置的状态 if ((next_x >= 0 && next_x <= 7) && (next_y >= 0 && next_y <= 7)) { next_site += next_step[j][0] - 8 * next_step[j][1];//注意此处的变化 next_status = status - (now_site << (6 * (2 - i))) + (next_site << (6 * (2 - i)));//修改对应位置的状态 } else return -1; return next_status; } bool checkOK(int status) { //若三个位置相同,则找到一个结果 return (((status & 0x3F) == ((status >> 6) & 0x3F)) && ((status >> 6) & 0x3F) == ((status >> 12) & 0x3F)); } int solve() { char s[7]=""; start[0][0] = start[0][0] - 'A' + '0'; start[1][0] = start[1][0] - 'A' + '0'; start[2][0] = start[2][0] - 'A' + '0'; start[0][1] = start[0][1] - '1' + '0'; start[1][1] = start[1][1] - '1' + '0'; start[2][1] = start[2][1] - '1' + '0'; strcat(s, start[0]); strcat(s, start[1]); strcat(s, start[2]); //cout << s << endl; //cout << strtol(s,NULL,8)<< endl; now_status = strtol(s, NULL, 8);//按八进制转换为十进制整数 if (checkOK(now_status)) { return 0;//开始状态符合,返回0 } memset(step,-1,sizeof(step));//按字节初始化,只能为0或-1 step[now_status] = 0; //清空队列 while (!q.empty()) q.pop(); q.push(now_status); while (!q.empty()) { now_status = q.front(); q.pop(); for (int i = 0; i < 3; ++i) for (int j = 0; j < 8; ++j) { next_status = move(now_status, i, j); if (next_status != -1 && step[next_status] == -1) { step[next_status] = step[now_status] + 1; q.push(next_status); if (checkOK(next_status)) { return step[next_status]; } } } } return 0; } int main() { int t; cin >> t; while (t--) { cin >> start[0] >> start[1] >> start[2]; cout << solve() << endl; } return 0; }