N-Rooks解决方案回溯数量

时间:2016-12-09 06:28:16

标签: c++ algorithm backtracking

这些方法应该用于计算任何数量的车在非攻击安排中可能在板上的安排。 我知道我必须在这里丢失一些愚蠢的东西。帮帮我。出于某种原因,我的返回解决方案计数已关闭,即使已找到打印报表6解决方案...我已尝试打印阵列,在找到解决方案时打印...我找不到任何内容这有帮助。

编辑*:用户界面不完整。忽略其中的错误。更关心我从findnumsolution()方法得到的错误结果。我试过通过构造函数直接传递值,它仍然给我错误的答案。 3x3板,3件,返回5,4x4,4个返回13。

编辑**:清除不相关的代码。

NRooks(int board[8][8], int n, int k)
{
    numRooks = n;
    boardSize = k;
    numSolutions = 0;
    for(int i = 0; i < 8; i++)
        for(int j = 0; j < 8; j++)
            board[i][j] = 0;
    numSolutions = findNumSolutions(board, 0, numRooks);
}

bool canPlace(int col, int row, int board[8][8])
{
    for(int i = col-1; i >= 0; i--){
        if(board[i][row] == 1){
            return false;
        }
    }
    return true;
}

int findNumSolutions(int board[8][8], int col, int rooksLeft)
{
   if(col > boardSize||rooksLeft ==0)
       return 1;
   int nsolutions = 0;
   for(int i = 0; i < boardSize; i++){
        board[col][i] = 1;
        if(!canPlace(col, i, board)){
            continue;
        }
        nsolutions += findNumSolutions(board, col + 1, rooksLeft - 1);
        board[col][i] = 0;
    }
    return nsolutions;
}

3 个答案:

答案 0 :(得分:2)

我没有教这个代码的错误,但我有更有效的解决方案,没有回溯。这只是一个数学问题。

这个问题是:给定整数N和K,找到将N个车放入K * K板的方式。

如果N> K,答案是零 如果N = K,答案是K!。因为您可以在每列中选择一个车,所以方式的数量等于p={1, 2, 3,..., K}的排列数量
让我们考虑一下N&lt; K案件。
实际上,答案是P(K, N) * C(K, N)。 如果电路板尺寸为N * K,则只能选择满足1&lt; = p [i]&lt; = K且p [i]不同的置换。
所以有P(K, N)种方式 您还可以在K行中选择N行来放置车辆。并且有C(K, N)种方式。
然后,最终答案是P(K, N) * C(K, N)

如果您不知道P(置换)或C(组合),请阅读here
最后,如果N <= K,则答案为P(K, N) * C(K, N),否则答案为零 时间复杂度为O(K),并且优于O(P(K, N) * C(K, N))强力算法。

答案 1 :(得分:0)

现在修复的第一个错误是你在递归函数中使用成员变量,你应该使用局部变量。这里有两种变体:从每次调用返回数字或者具有全局或成员函数并在那里累积解决方案。不要混用这些方法。

第二个错误,原始帖子中没有,但是当您发布整个代码时引入的错误在此处:

// try placing piece in row of col
for(int i = 0; i < boardSize; i++){
    board[col][i] = 1;
    if(!canPlace(col, i, board)){
        continue;
    }
    nsolutions += findNumSolutions(board, col + 1, rooksLeft - 1);
    board[col][i] = 0;
}

这相当于:

// try placing piece in row of col
for (int i = 0; i < boardSize; i++){
    board[col][i] = 1;
    if (canPlace(col, i, board)) {
        nsolutions += findNumSolutions(board, col + 1, rooksLeft - 1);
        board[col][i] = 0;
    }
 }

车的设置和恢复必须是对称的;也就是每次放置车辆时,你必须在尝试放置新车之前或者在再次重新提起之前休息。您可以看到每个箱子都放置了车,但只有在可以放置时才清理。这导致车上的车辆数量超过应有的数量。

您的支票不考虑当前列,因此您可以将两个车位放置在支架外或两者内部。我建议:

for (int i = 0; i < boardSize; i++){
    if (canPlace(col, i, board)) {
        board[col][i] = 1;
        nsolutions += findNumSolutions(board, col + 1, rooksLeft - 1);
        board[col][i] = 0;
    }
}

作为附录,我认为班级应该管理自己的董事会。这将消除许多令人困惑的board参数。如果您在堆上分配电路板大小,则也不需要MAXSIZE。但要注意:当电路板尺寸变大时,安排的数量将超过int

#include <iostream>

class NRooks {
public:
    NRooks(int n, int k);
    ~NRooks();

    int getSolutionTotal();

private:
    bool canPlace(int col, int row);
    int findNumSolutions(int col, int rooksLeft);

    int numSolutions;
    int numRooks;
    int boardSize;
    int *data;
    int **board;
};

NRooks::NRooks(int n, int k)
{
    numRooks = n;
    boardSize = k;
    numSolutions = 0;

    data = new int[k*k];
    board = new int*[k];

    for (int i = 0; i < k; i++) board[i] = data + k*i;
    for (int i = 0; i < k*k; i++) data[i] = 0;

    numSolutions = findNumSolutions(0, numRooks);
}

NRooks::~NRooks()
{
    delete[] data;
    delete[] board;
}

int NRooks::getSolutionTotal(){
    return numSolutions;
}

bool NRooks::canPlace(int col, int row)
{
    for (int i = col; i-- > 0; ) {
        if (board[i][row]) return false;
    }

    return true;
}

int NRooks::findNumSolutions(int col, int rooksLeft)
{
    if (rooksLeft == 0) return 1;
    if (col > boardSize) return (rooksLeft == 0);

    int nsolutions = 0;

    for (int i = 0; i < boardSize; i++) {
        if (canPlace(col, i)) {
            board[col][i] = 1;
            nsolutions += findNumSolutions(col + 1, rooksLeft - 1);
            board[col][i] = 0;
        }
    }

    if (rooksLeft < boardSize - col) {
        nsolutions += findNumSolutions(col + 1, rooksLeft);
    }

    return nsolutions;
}

int main()
{
    for (int boardSize = 2; boardSize <= 6; boardSize++) {
        for (int numPieces = 1; numPieces <= boardSize; numPieces++) {
            NRooks r = NRooks(numPieces, boardSize);

            std::cout << boardSize << " board, "
                      << numPieces << " rooks, "
                      << r.getSolutionTotal() << " solutions" 
                      << std::endl;
        }
    }

    return 0;
}

答案 2 :(得分:0)

我正在使用square1001

描述的方法
#include <iostream>
using namespace std;

long long fact(int n)
{
    long long factorial=1;
    if(n<=0)
    {
        return 1;
    }
    for(int i=1; i<=n; ++i)
    {
        factorial *= i;              // factorial = factorial*i;
    }
    return factorial;
}
long long permutation(int n, int r) {
    if( n<=0 || r<= 0)
    {
        return 1;
    }
    return fact(n)/fact(n-r);
}

long long combination(int n, int r) {
    if(r > n / 2) r = n - r; // because C(n, r) == C(n, n - r)
    long long ans = 1;
    int i;

    for(i = 1; i <= r; i++) {
        ans *= n - r + i;
        ans /= i;
    }

    return ans;
}

long long findNumSolutions(int boardSize,int numberofRooks)
{
    if(numberofRooks>boardSize || numberofRooks <=0)
    {
        return 0;
    }
    long long comb=combination(boardSize,numberofRooks);
    long long  perm=permutation(boardSize,numberofRooks);
    cout<<"comb : "<<comb<<endl;
    cout<<"perm : "<<perm<<endl;
    return comb*perm;
}

int main ()
{
  std::cout <<findNumSolutions(3,3)<<endl;

  return 0;
}