C++ 幻方和回溯C++;
我必须写一个程序来解一个NxN幻方,数字从1到N^2。 它适用于3x3,部分填充4x4,但在两小时内,它无法找到部分填充5x5的解决方案 这是我的代码: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
#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]
之前一样,网格应该是正确的,您可以只测试RowRow
和colnCol
(以及对角线)而不是整个网格。因此,代码变成:
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常量
)填充列/行/对角线,跟踪速度就会更快.CheckInvalidSumCheckInvalidSum
无效,我将添加此方法的一些代码。好的,非常感谢。我正在研究新代码,我将向您更新我的进度:)@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;
}