概率算法实现八皇后问题-cpp

找出 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为皇后数量。
概率算法实现八皇后问题-cpp_第1张图片

你可能感兴趣的:(概率算法实现八皇后问题-cpp)