被困在n*n棋盘上q个主教的算法上
Getting Stuck On the Algorithm for q bishops on an n*n chessboard
我使用的是C++,但我的问题更多的是算法而不是实现。
问题如下:
编写一个程序,输入两个整数n和k,其中n>=k。你的程序应该计算出在nXn棋盘上放置k个主教的不同方式的数量。
我的基本想法是将每个bishop表示为具有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函数结束时不断被调用,直到它达到一个循环。但我不知道该用什么算法来找到下一个解决方案。
将bishop位置存储在数组中的想法有了一个良好的开端。这是一个董事会状态的紧凑表示。
你必须纠正你检查一个主教是否与另一个主教冲突的方法。请记住,两个冲突的主教可以由垂直距离dy
和水平距离dx
分开,使得CCD_。因此,您需要比较绝对值:如果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
为了避免递归调用的指数级爆炸,您需要缓存每个子问题的结果。这种技术被称为记忆,您可以按如下方式实现它。
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
的密钥时,您可以通过对主教位置进行排序或制作板的位图来实现这一点。
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 基于ELO的团队匹配算法
- C++选择排序算法中的逻辑错误
- 有没有办法将谓词中的元素偏移量传递给 std 算法?
- C++A*算法并不总是在路径中具有目标节点
- 排序算法c++
- 构建可组合有向图(扫描仪生成器的汤普森构造算法)
- 算法问题:查找从堆栈中弹出的所有序列
- 下面是排序算法O(n)吗
- KMP算法和LPS表构造的运行时间
- 为什么我的排序算法会更改数组值
- 求最大元素位置的分治算法
- 具有非整数边容量的最大流量的Dinic算法
- 到连接组件算法的问题(递归)
- STL算法函数在多个一维容器上的使用
- 读取最后一行代码算法 - c++ 时出现问题
- 括号更改 O(n) 算法
- std::unordered_map 搜索算法是如何实现的?
- 如何实现高效的算法来计算大型数据集的多个不同值?
- 如何在 Mac 上使用 c++17 并行标准库算法?