C++ 幻方和回溯C++;

C++ 幻方和回溯C++;,c++,backtracking,magic-square,C++,Backtracking,Magic Square,我必须写一个程序来解一个NxN幻方,数字从1到N^2。 它适用于3x3,部分填充4x4,但在两小时内,它无法找到部分填充5x5的解决方案 这是我的代码: #include <iostream> #include <fstream> #include <string.h> const int N = 3; const int Possibili_N = N*N; const int Magic_Constant = (N*((N*N)+1))/2; usin

我必须写一个程序来解一个NxN幻方,数字从1到N^2。 它适用于3x3,部分填充4x4,但在两小时内,它无法找到部分填充5x5的解决方案

这是我的代码:

#include <iostream>
#include <fstream>
#include <string.h>

const int N = 3;
const int Possibili_N = N*N;
const int Magic_Constant = (N*((N*N)+1))/2;

using namespace std;

class MagicSquare{
    bool Num_Possibili[Possibili_N];  // true se non è stato preso, false se è stato preso
    int Square[N][N];
    int BackTracking_Cicle;
    int N_Square;

    void Set_NumPossibili();
    bool SearchEmpty(int &Row, int &Col);
    bool CheckSum();
    bool CheckRows();
    bool CheckCols();
    bool CheckDiags();
    void Set_BackTrackingCicle()        { BackTracking_Cicle = 0;};
    void Increase_BackTrackingCicle()   { BackTracking_Cicle++; };
    void Set_NSquare()                  { N_Square = 0;};
    void Increase_NSquare()             { N_Square++; };

public:
    MagicSquare(){};
    ~MagicSquare(){};
    bool Set_MagicSquare(string FilePath);
    bool Calc_MagicSquare();
    void Stamp_MagicSquare();
    int Get_BackTrackingCicle()         { return BackTracking_Cicle; };
    int Get_NSquare()                   { return N_Square; }
};
bool MagicSquare::Set_MagicSquare(string FilePath)
{   ifstream StartFile;
    StartFile.open(FilePath.c_str(), ios::in);
    string Buffer;

    if(StartFile.is_open())
    {   Set_NumPossibili();
        Set_BackTrackingCicle();
        Set_NSquare();

        for(int i=0; i<N; i++)
        {   getline(StartFile, Buffer);

            for(int j=0, k=0; j<N; j++, k+=3)
            {   Square[i][j] = ((Buffer[k]-'0')*10)+(Buffer[k+1]-'0');

                if(Square[i][j] != 0)
                    Num_Possibili[Square[i][j]-1] = false;
            }
        }

        StartFile.close();
        return true;
    }
    else
        return false;
}

void MagicSquare::Set_NumPossibili()
{   for(int i=0; i < Possibili_N; i++)
        Num_Possibili[i] = true;
}

void MagicSquare::Stamp_MagicSquare()
{   for(int i=0; i<N; i++)
    {   for(int j=0; j<N; j++)
            if(Square[i][j] == 0)
                cout << '-' << "\t";
            else
                cout << Square[i][j] << "\t";
        cout << endl;
    }
    cout << endl;
}

bool MagicSquare::Calc_MagicSquare()
{   int Row, Col;

    if(SearchEmpty(Row, Col))
    {   for(int i=0; i < Possibili_N; i++)
        {   if(Num_Possibili[i])
            {   Square[Row][Col] = i+1;
                Num_Possibili[i] = false;

                Calc_MagicSquare();

                // Backtracking
                Square[Row][Col] = 0;
                Num_Possibili[i] = true;
                Increase_BackTrackingCicle();
            }
        }
    }
    else
    {   if(CheckSum())
        {   Stamp_MagicSquare();
            Increase_NSquare();
        }
    }

    return false;
}

bool MagicSquare::SearchEmpty(int &Row, int &Col)
{   for(Row=0; Row<N; Row++)
        for(Col=0; Col<N; Col++)
            if(Square[Row][Col] == 0)
                return true;
    return false;
}

bool MagicSquare::CheckSum()
{   if(CheckDiags() && CheckRows() && CheckCols())
        return true;
    return false;
}

bool MagicSquare::CheckRows()
{   bool Check = true;

    for(int i=0, j, Sum; i<N && Check; i++)
    {   j=0; Sum=0;

        while(j<N)
        {   Sum += Square[i][j];
            if(Square[i][j] == 0)
                return false;
            j++;
        }
        if(Sum == Magic_Constant)
            Check = true;
        else
            Check = false;
    }

    return Check;
}

bool MagicSquare::CheckCols()
{   bool Check = true;

    for(int i=0, j, Sum; i<N && Check; i++)
    {   j=0; Sum=0;

        while(j<N)
        {   Sum += Square[j][i];
            if(Square[j][i] == 0)
                return false;
            j++;
        }

        if(Sum == Magic_Constant)
            Check = true;
        else
            Check = false;
    }

    return Check;
}

bool MagicSquare::CheckDiags()
{   bool Check = false;
    int Sum = 0;

    for(int i=0, j=0; i<N; i++, j++)
    {   Sum += Square[i][j];

        if(Square[i][j] == 0)
            return false;
    }

    if(Sum == Magic_Constant)
    {   Sum = 0;
        for(int i=N-1, j=0; i>=0; i--, j++)
        {   Sum += Square[i][j];

            if(Square[i][j] == 0)
                return false;

            if(Sum == Magic_Constant)
                Check = true;
            else
                Check = false;
        }
    }

    return Check;
}

int main()
{   MagicSquare Puzzle;
    string FilePath = "PartialSquare.txt";


    if(Puzzle.Set_MagicSquare(FilePath))
    {   Puzzle.Stamp_MagicSquare();

        cout << "La Costante Magica di un quadrato " << N << "x" << N;
        cout << " e': " << Magic_Constant << endl;

        Puzzle.Calc_MagicSquare();

        cout << "Numero di Quadrati Magici trovati: " << Puzzle.Get_NSquare() << endl;
        cout << "Numero di Cicli di Backtracking: " << Puzzle.Get_BackTrackingCicle() << endl;
    }
    else
        cout << "Errore nell'apertura del file." << endl;

    return 0;
}
提前感谢。

Calc_MagicSquare()
中,您可以在行/列/诊断无效时立即停止探索:

if (Num_Possibili[i]) {
    Square[Row][Col] = i + 1;
    Num_Possibili[i] = false;

    if (CheckInvalidSum()) {
        // Backtracking
        Increase_BackTrackingCicle();
    } else {
        // Continue exploration
        Calc_MagicSquare();
    }
    // restore State.
    Square[Row][Col] = 0;
    Num_Possibili[i] = true;
}
使用
CheckInvalidSum()
,当行/列/诊断已满(而不是
0
)且总和不同于
Magic_常量时,返回
true

int RowSum(int row) const
{
    int sum = 0;

    for (int col = 0; col != N; ++col) {
        sum += Square[row][col];
    }
    return sum;
}

bool IsRowFull(row) const
{
    for (int col = 0; col != N; ++col) {
        if (Square[row][col] == 0) {
            return false;
        }
    }
    return true;
}

bool CheckInvalidSum() const
{
    for (int row == 0; row != N; ++row) {
         if (IsRowFull(row) && RowSum(row) != Magic_Constant) {
              return true; 
         }
    }
    // Similar stuff for column and diag
    return false;
}
优化注意:正如在修改
Square[Row][Col]
之前一样,网格应该是正确的,您可以只测试Row
Row
和coln
Col
(以及对角线)而不是整个网格。因此,代码变成:

bool CheckInvalidSum(int row, int col) const
{
    if (IsRowFull(row) && RowSum(row) != Magic_Constant) {
         return true; 
    }
    // Similar stuff for column and diag
    return false;
}
这是新代码:

bool MagicSquare::Calc_MagicSquare()
{   int Row, Col;

    if(SearchEmpty(Row, Col))
    {   for(int i=0; i < Possibili_N; i++)
        {   if(Num_Possibili[i])
            {   Square[Row][Col] = i+1;
                Num_Possibili[i] = false;

                if(!CheckInvalidSum())
                    Calc_MagicSquare();

                // BackTracking
                Square[Row][Col] = 0;
                Num_Possibili[i] = true;
                Increase_BackTrackingCicle();
            }
        }
    }
    else
        if(CheckSum())
        {   Stamp_MagicSquare();
            Increase_NSquare();
        }

    return false;
}
bool MagicSquare::Calc_MagicSquare()
{int行,Col;
如果(搜索空(行、列))
{for(int i=0;i
这是另一种方法:

bool MagicSquare::CheckInvalidSum()
{   int Sum=0;

    //Check Row
    for(int i=0; i<N; i++)
        for(int j=0; j<N; j++)
        {   if(Square[i][j] == 0)
                return true;
            Sum += Square[i][j];
        }

    if(Sum != Magic_Constant)
        return true;

    // Check Col
    Sum = 0;
    for(int i=0; i<N; i++)
        for(int j=0; j<N; j++)
        {   if(Square[j][i] == 0)
                return true;
            Sum += Square[j][i];
        }

        if(Sum != Magic_Constant)
            return true;

        return false;
    }
bool MagicSquare::CheckInvalidSum()
{int Sum=0;
//检查行

对于(int i=0;iYou可能希望改为发布。这里的链接:)@JoachimPileborg不清楚5x5案例是否会结束,这使得无法将此代码归类为“正在工作”。这与代码审查无关。@Jarod42这里是:有17个空空间,您正在寻找17!(355687428096000)网格。只要用错误的和(而不是
Magic\u常量
)填充列/行/对角线,跟踪速度就会更快.CheckInvalidSum
CheckInvalidSum
无效,我将添加此方法的一些代码。好的,非常感谢。我正在研究新代码,我将向您更新我的进度:)@Jarod42它在部分填充5x5、6x6和空4x4的情况下正常工作。但是,我有一个疑问:我应该将增量放在哪里;正确计算回溯周期?谢谢:)
回溯发生在网格被拒绝或接受时,所以当
CheckInvalidSum()==true
或网格已满时。那么,它是否位于正确的位置?当
CheckInvalidSum()==true
或从递归返回时,它会增加周期。。。
bool MagicSquare::CheckInvalidSum()
{   int Sum=0;

    //Check Row
    for(int i=0; i<N; i++)
        for(int j=0; j<N; j++)
        {   if(Square[i][j] == 0)
                return true;
            Sum += Square[i][j];
        }

    if(Sum != Magic_Constant)
        return true;

    // Check Col
    Sum = 0;
    for(int i=0; i<N; i++)
        for(int j=0; j<N; j++)
        {   if(Square[j][i] == 0)
                return true;
            Sum += Square[j][i];
        }

        if(Sum != Magic_Constant)
            return true;

        return false;
    }