找出 n=12~20 时最优的 StepVegas值
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int N = 12;
bool backtrace(int &k, set &col, set &diag45, set &diag135, bool &success, vector &placeCol);
void QueensLv(bool &success, const int stepVegas);
int main()
{
bool success = false;//记录一次QueensLv函数调用是否放置皇后成功
clock_t start, finish;//记录起止时间
double duration = 0.0;//记录耗时
int FailCnt = 0;//记录执行1000次八皇后放置成功期间的失败次数
//循环N:12-20
while (N <= 20)
{
//stepVagas循环0-N
for (int stepVegas = 1; stepVegas < N; stepVegas++)
{
FailCnt = 0;
//循环执行成功1000次;
int loopInt = 1000;
start = clock();
while (loopInt--)
{
success = false;
while (!success)
{
QueensLv(success, stepVegas);
if (!success)
FailCnt++;
}
}
finish = clock();
//循环执行1000次成功的时间
duration = (double)(finish - start) / CLOCKS_PER_SEC;
cout << "N = " << setw(3) << setiosflags(ios::left) << N;
cout << " StepVegas = " << setw(3) << setiosflags(ios::left) << stepVegas;
cout << " Fail times = " << setw(6) << setiosflags(ios::left) << FailCnt;
cout << " spend Time = " << setw(6) << setiosflags(ios::left) << duration << " s" << endl;
}
cout << endl;
N++;
}
return 0;
}
bool backtrace(int &k, set &col, set &diag45, set &diag135, bool &success, vector &placeCol)
{
int i = 1;
int startK = k;
while (k <= N && k >= startK)
{
while (i <= N)
{
//不同列,不在45度角,不在135度角
if ((!col.count(i)) && (!diag45.count(i - k)) && (!diag135.count(i + k)))
{
//放置皇后
placeCol[k] = i; //记录第k行,j列已经放置皇后
col.insert(i);
diag45.insert(i - k);
diag135.insert(i + k);
//更新行
k++;
i = 1;
break;
}
i++;
}
if (i > N)
{
//移去皇后
k--;
//移去改行放置的皇后
col.erase(placeCol[k]);
diag45.erase(placeCol[k] - k);
diag135.erase(placeCol[k] + k);
i = placeCol[k] + 1;//以该皇后所在列的下一列作为当前列
placeCol[k] = 0;//将前一行,j列已经放置皇后恢复
}
}
//回溯结束条件
if (k == N + 1)
success = true;
else
success = false;
return success;
}
void QueensLv(bool &success, const int stepVegas)
{
set col, diag45, diag135;
int k = 1, nb = 0, j = 0;
vector placeCol(N + 1, 0);
srand(time(0));
while (k <= stepVegas)//随机放置的皇后数
{
nb = 0;//记录当前皇后可以放置的有效位置数量
vector effectivePos;//记录当前行可以放置的皇后位置
for (int i = 1; i <= N; i++)
{
if ((!col.count(i)) && (!diag45.count(i - k)) && (!diag135.count(i + k)))
{
nb++;
effectivePos.push_back(i);
}
}
if (nb > 0)
{
int pos = rand() % nb;
j = effectivePos[pos];//随机选择一个有效位
//放置皇后
placeCol[k] = j;
col.insert(j);
diag45.insert(j - k);
diag135.insert(j + k);
k++;//开始放置下一行
success = true;
}
else if (nb == 0)
{
success = false;
return;
}
}
if (nb > 0 || stepVegas == 0)//stepVegas为0,纯回溯或者随机放置stepVegas行的皇后之后采用回溯法放置接下来的皇后。
{
success = backtrace(k, col, diag45, diag135, success, placeCol);
}
else
success = false;
return;
}
效率对比
比如19个皇后问题,算法时间对比,stepVegas=0,表示纯回溯法,可以看到stepVegas等于18时,即随机放置18个皇后,再采取回溯法,效率是前者的几百,上千倍,然后同数量级在N/2左右有6,皇后数量越多,概率算法效率更加凸显。一般最优 stepVegas不具规律性,但是一般在接近N/2附近,N为皇后数量。