zoukankan      html  css  js  c++  java
  • 概率算法实现八皇后问题-cpp

    找出 n=12~20 时最优的 StepVegas值

    #include <ctime>
    #include <float.h>
    #include <iomanip>
    #include <iostream>
    #include <math.h>
    #include <random>
    #include <set>
    #include <vector>
    
    using namespace std;
    
    int N = 12;
    
    bool backtrace(int &k, set<int> &col, set<int> &diag45, set<int> &diag135, bool &success, vector<int> &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<int> &col, set<int> &diag45, set<int> &diag135, bool &success, vector<int> &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<int> col, diag45, diag135;
        int k = 1, nb = 0, j = 0;
        vector<int> placeCol(N + 1, 0);
        srand(time(0));
        while (k <= stepVegas)//随机放置的皇后数
        {
            nb = 0;//记录当前皇后可以放置的有效位置数量
            vector<int> 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为皇后数量。

  • 相关阅读:
    3. 无重复字符的最长子串
    字节跳动 最小栈
    排序
    线程的优先级
    线程的操作方法
    线程的生命周期
    实现线程的方式:Thread类重写run();Runnable类重写run();Callable类重写call();实现线程的方式
    Java thread run() start() 是干什么的以及区别
    Java thread 多线程
    助教工作学期总结
  • 原文地址:https://www.cnblogs.com/Alexkk/p/12778774.html
Copyright © 2011-2022 走看看