有一个无限的棋盘,
在控制台上,我们输入将有多少个示例,棋盘上有多少个国际象棋骑士,他们的起始位置(即,他们的位置),以及骑士必须经过最少的步骤才能到达的点。
它应该是这样的:
2
-示例数量1
-国际象棋骑士的人数5 5
-起点5 6
-最后一点2
-国际象棋骑士的人数0 0
-第一个骑士的起点1 0
-第二个骑士的起点0 1
-第一个骑士的终点站1 1
-第二个骑士的终点答案:
3
-第一个示例的答案4
-第二个示例的答案问题在于它无法解决问题,因为使用第一个数据集,一切都很好,但是使用第二个数据集,则无法得出正确的答案。
如果我们分开计算分数,那么第二个数据集中的答案是6(第一个骑士3个,第二个骑士3个)。
我猜想如何解决它,但它不起作用。
猜想是,当第二个骑士开始移动时,它经过的点与第一个骑士通过的点相同(第二个示例),并且如果第一个骑士已经在这些位置,则可能需要写下条件,然后第二个不能再通过。
第二个猜想是,您需要写下棋盘的条件并使其不受限制,并使骑士步行棋盘的负值。
这是示例照片(下):
请帮助,我将非常感谢!!!
#include <iostream>
#include <set>
#include <queue>
#include <climits>
using namespace std;
#define N 8
// Below arrays details all 8 possible movements
// for a knight
int row[] = { 2, 2, -2, -2, 1, 1, -1, -1 };
int col[] = { -1, 1, 1, -1, 2, -2, 2, -2 };
// Check if (x, y) is valid chess board coordinates
// Note that a knight cannot go out of the chessboard
bool valid(int x, int y)
{
if (x < 0 || y < 0 || x >= N || y >= N)
return false;
return true;
}
// queue node used in BFS
struct Node
{
// (x, y) represents chess board coordinates
// dist represent its minimum distance from the source
int x, y, dist;
// Node constructor
Node(int x, int y, int dist = 0): x(x), y(y), dist(dist) {}
// As we are using struct as a key in a std::set,
// we need to overload < operator
// Alternatively we can use std::pair<int, int> as a key
// to store coordinates of the matrix in the set
bool operator<(const Node& o) const
{
return x < o.x || (x == o.x && y < o.y);
}
};
// Find minimum number of steps taken by the knight
// from source to reach destination using BFS
int BFS(Node src, Node dest)
{
// set to check if matrix cell is visited before or not
set<Node> visited;
// create a queue and enqueue first node
queue<Node> q;
q.push(src);
// run till queue is not empty
while (!q.empty())
{
// pop front node from queue and process it
Node node = q.front();
q.pop();
int x = node.x;
int y = node.y;
int dist = node.dist;
// if destination is reached, return distance
if (x == dest.x && y == dest.y)
return dist;
// Skip if location is visited before
if (!visited.count(node))
{
// mark current node as visited
visited.insert(node);
// check for all 8 possible movements for a knight
// and enqueue each valid movement into the queue
for (int i = 0; i < 8; ++i)
{
// Get the new valid position of Knight from current
// position on chessboard and enqueue it in the
// queue with +1 distance
int x1 = x + row[i];
int y1 = y + col[i];
if (valid(x1, y1))
q.push({x1, y1, dist + 1});
}
}
}
// return INFINITY if path is not possible
return INT_MAX;
}
// main function
int main()
{
// source coordinates
Node src = {0, 7};
// destination coordinates
Node dest = {7, 0};
cout << "Minimum number of steps required is " << BFS(src, dest);
return 0;
}
答案 0 :(得分:1)
根据您提供的数据,两个骑士应该这样移动:
但是,在您的图表中,您暗示骑士应该这样移动(忽略丢失了1
的错误x轴):
您的图表将每个骑士移动到另一个骑士的最终位置,这是不正确的。您的代码为6
提供了正确的解决方案,以根据您提供的数据将每个骑士移至其最终位置。
答案 1 :(得分:0)
这是一个假定终点位置未链接到骑士的答案(任何骑士都可以以任何终点位置结束)。这是一个与编程语言无关的算法问题,因此我不会显示任何代码。
最简单但效率最低的方法是假设每个骑士都有一个所需的最终位置。您通过索引将最终位置的所有排列分配给骑士,并为每个排列计算结果。最后,您返回最小结果。在您的示例中,一个结果将是6
(原始映射),另一个结果将是4
(交换最终位置,唯一的其他排列),因此您将得到4
。这种方法的问题是对于 n 个骑士,您需要考虑 n!个排列。
贪婪的方法是让每个骑士移动直到到达最后一个地点,然后让另一个跳到另一个地点。这将对您的示例有效,但在此示例中会出错:
第一个骑士会移动
完成(1步),第二个骑士将不得不移动
这需要4个步骤,总共需要5
。但是,最佳解决方案是:
这是3个步骤。因此,我们看到,幼稚的贪心算法不一定能产生正确的结果。
但是,我们可以采用贪婪的方法做得更好:首先,计算每个骑士/最终位置对之间的距离,并存储它们(使用原始算法)。
我们之前的示例如下:
(5,4) <- first knight
(3,3) = 1 <- distance to first final position
(9,6) = 2 <- distance to second final position
(2,1) <- second knight
(3,3) = 1
(9,6) = 4
计算完这些后,该算法随后将为骑士分配一个终点位置。它将像这样工作:
环回尚未结束的所有骑士。对于每个骑士,标记最近的最终位置并计算其他骑士的罚分。罚款是尚未分配的所有其他骑士的附加动作的最大值。例如,为(3,3)
的骑士选择(5,4)
将受到 3 的惩罚,因为另一个骑士现在将需要再移动3步(因为我们将其标记为最近最终位置)。但是,为(3,3)
的骑士选择(2,1)
会受到 1 的惩罚,因为另一个骑士只需要再移动一个步骤即可。
计算所有惩罚后,将惩罚最小的骑士分配给其最近的最终位置。循环直到所有骑士都被分配了最终位置。
此算法对于您的原始示例和我的示例都是正确的,但是我不知道它是否总是正确的。您需要证明这一点。