我正在使用C++,但是我的问题更多是关于算法而不是实现。

问题如下:



我的基本思想是将每个主教表示为具有X值和Y值的结构。然后,我将主教放在板上以进行配置。

我编写了一个名为moveToNextPlace的方法,该方法使我可以将主教移动到下一个可用位置。我返回一个字符串来帮助调试。

struct bishop {
int y=0;
int x=0;
string moveToNextPlace (int n){
    if (y<n-1) {y++; return "move to next y value";}
    else if (x<n-1) {x++; return "move to next x value";}
    else {reset(); return "reset";};
}
void setValuesLike (bishop b){
    y=b.y;
    x=b.x;
}
void reset (){
    y=0;
    x=0;
}
bool clashesWith (bishop b){
    if (b.x==x && b.y==y){
        return true;
    }
    if ( b.y-y == b.x-x ) return true; //if their slope is 1
    return false;

}
};

然后,通过使用所需的设置调用findSolutions将板设置为初始配置。
int findSolutions (int k, int n){ //k bishops on n*n board
bishop *b = new bishop [k];
for (int i=0; i<k; i++){
    findAspot (b, n, i);
}
}

bool check (int num, bishop b[]){
for (int i=0 ; i<num; i++){
    if (b[i].clashesWith (b[num])) return false;
}
return true;
}

void findAspot (bishop b[], int n, int num){ //n=boardsize
while (1){
    if (check(num, b)){return;}
    if (b[num].moveToNextPlace(n) == "reset") break;
}
b[num-1].moveToNextPlace(n);
findAspot (b, n, num-1);
b[num].setValuesLike ( b[num-1] );
findAspot (b, n, num);

}

然后,我想一直往回走,直到找到总数解决方案为止,但是我在如何找到下一个解决方案上陷入了困境。

我以为我可以写一个findNextSolution,它会在findSolutions函数的末尾不断被调用,直到到达一个循环为止。但是我不知道该使用哪种算法来找到下一个解决方案。

最佳答案

将主教职位存储在数组中的想法是一个不错的开端。这是板状态的紧凑表示。

您必须更正检查一个主教是否与另一个主教发生冲突的方法。请记住,两个相互冲突的主教可能被垂直距离dy和水平距离dx分隔为dx == -dy。因此,您将需要比较绝对值:如果abs(dx) == abs(dy),则主教会发生冲突。

现在讨论计数k主教不冲突的棋盘状态数的一般问题。您将需要定义一个返回整数值的函数。假设这个功能看起来像

count(currentBishops, numRemaining)

其中currentBishops是可行的主教位置,而numRemaining是尚未放置的主教数量。

那么问题的解决方案是
count([], k)

其中[]表示尚未放置任何主教。
count函数可以根据以下伪代码实现。
count(currentBishops, numRemaining):
  if numRemaining == 0:
    return 1
  sum = 0
  for each possible board position (x, y):
    if (x, y) does not clash with any bishop in currentBishops:
      let nextBishops be currentBishops augmented with (x, y)
      sum += count(nextBishops, numRemaining-1)
  return sum

为了避免递归调用呈指数级增长,您将需要缓存每个子问题的结果。该技术称为memoization,您可以按以下方式实现它。
let memo be a map from (currentBishops, numRemaining) to an integer value

count(currentBishops, numRemaining):
  if numRemaining == 0:
    return 1
  if memo contains (currentBishops, numRemaining):
    return memo[(currentBishops, numRemaining)]
  sum = 0
  for each possible board position (x, y):
    if (x, y) does not clash with any bishop in currentBishops:
      let nextBishops be currentBishops augmented with (x, y)
      sum += count(nextBishops, numRemaining-1)
  memo[(currentBishops, numRemaining)] = sum
  return sum
currentBishops的映射应该不关心主教的放置顺序。在计算memo的 key 时,可以通过对主教位置进行排序或对面板进行位图来完成此操作。

08-20 02:41