描述
国际象棋棋盘上有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;
}