【问题标题】:Getting Stuck On the Algorithm for q bishops on an n*n chessboard陷入 n*n 棋盘上 q 个主教的算法
【发布时间】:2015-07-02 10:10:33
【问题描述】:

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

问题如下:

编写一个程序,输入两个整数 n 和 k,其中 n>=k。你的程序应该计算出 k 个象可以放在 nXn 棋盘上的不同方式的数量。

我的基本想法是将每个主教表示为具有 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 函数结束时一直被调用,直到它到达一个循环。但我不知道用什么算法来寻找下一个解决方案。

【问题讨论】:

  • 几乎没有。比较 programmers.stackexchange.com/help/on-topicstackoverflow.com/help/on-topic。一个特别提到算法,另一个则称任何与实现相关的题外话。程序员适用于一般软件方法和过程的东西。 OP 是主题。
  • @Yigal - 你的意思是“放置在 (n,n) 棋盘上,这样没有人会按照通常的国际象棋规则检查任何其他人”,也许?
  • @Badzen 我会这样认为,因为如果你可以将它们放在任何地方,答案就很容易了。
  • @YigalSaperstein 你认为每行/列最多只能存在 1 个主教吗?
  • 我回答的问题让您满意吗?

标签: c++ algorithm search chess n-queens


【解决方案1】:

您将主教职位存储在数组中的想法有了一个良好的开端。这是棋盘状态的简洁表示。

您必须更正检查一位主教是否与另一位主教发​​生冲突的方法。请记住,两个冲突的主教可能被垂直距离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 的密钥时,您可以通过对主教位置进行排序或制作棋盘位图来完成此操作。

【讨论】:

  • 那么 currentBishops 应该是一个主教数组吗?还是一个 int- 并离开当前的主教全球? ---同样基于您的伪代码,它将返回两个交换的主教,作为两个不同的解决方案(换句话说:假设我们正在查看一个示例,其中 n=2 和 k=2。解决方案 1 将是(0, 0)和(1,0)和解决方案2将是(1,0)和(0,0)。)我想考虑那些1解决方案。因此,我正在考虑将所有解决方案存储在包含 2d 布尔数组的 vecor 中,仅在带有主教的地方标记为 true - 然后在添加到 sum 之前检查它......但我确信有一种 btr 方式
  • 再想一想,如果我将 currentbishops 作为一个仅包含主教职位的二维数组,我就可以用新的解决方案来确认旧的解决方案......很酷的想法。这可能就是你的意思我你的最后一句话
  • 我还在考虑一种不同类型的表示形式,它是一维 int 数组。这代表所有的主教 - 由一个 int 左上角的框是 1 左下角是 4 右下角是 16 右上角是 13。这意味着 value%n 将给出 y 并且 value/n 将给出 x..
  • 只要保持主教排序,就可以使用currentBishops 表示。这样,放置顺序就无关紧要了。或者,您可以将板存储为 2d 或 1d 数组。不管你选择什么表示,想一想:如果位置 (0, 0) 早于位置 (1, 0),你可以确保一旦你在 (1, 0) 放置了一个主教,你永远不会考虑放置一个再次在 (0, 0) 处进行主教。你知道怎么做吗?您可以查看您放置的最后一个主教,并从该位置开始迭代位置。
  • 我明白了……但是 currentBishop 应该是单身主教吗?还是一个向量或一个主教数组?和下一个主教。我不明白那个代表是什么?我在考虑向量并使用推回——所以当你说下一个主教时——我只是推回另一个被增强到 currentBishop 的主教。这种表示的问题是它不能正确递归。它只会产生一个巨大的向量。
猜你喜欢
  • 2021-12-15
  • 1970-01-01
  • 2014-02-03
  • 2016-03-11
  • 1970-01-01
  • 2017-05-27
  • 1970-01-01
  • 2022-11-23
  • 1970-01-01
相关资源
最近更新 更多