拉斯维加斯算法结合回溯法求解n后问题

实验8  

拉斯维加斯算法结合回溯法求解n后问题

设stopVgas为采用拉斯维加斯算法随机排设的皇后个数,对n、stopVgas进行多组不同取值时,记录程序成功率、运行时间

① 参考课件、教材、其它资料,将伪代码改成正式程序代码。

② 用一组小数据,手工验证程序正确性,发现可能的错误并修复。

③ 自己设计参数n、stopVgas的不同取值(可参考教材所给表格)。

④ 对不同参数进行运行,检测程序运行时间,观察并记录结果和发现。

前stop个随机放能放的位置,然后stop+1开始用回溯法放。

拉斯维加斯:比如四皇后,按回溯法第一个本该放在第一行第一列那个位置,现在用y数组保存第一行能放的位置,1、2、3、4都可以,y[]={1,2,3,4}。然后生成一个y数组内所有数范围内的随机数,比如2,那么现在第一个就放在了第一行第2列的位置。然后下一行(是按行一个一个放,第一个就是第一行那个,第二个就是第二行那个)就找能放的位置,第1、2、3列由于冲突对角线和列都不能放,y[]={4},就只能放在第二行第4列了(拿四皇后做例子是有点少哦)。

#include     
#include      
#include 
#include "RandomNumber.h"     
using namespace std;    
  
class Queen  
{  
    friend bool nQueen(int,int);  
private:  
    bool Place(int k);//测试皇后k置于第x[k]列的合法性  
    bool Backtrack(int t);//解n后问题的回溯法  
    bool QueensLV(int stopVegas);//随机放置n个皇后拉斯维加斯算法  
    int n,*x,*y,sv;  
};  
  
bool Queen::Place(int k)  
{//测试皇后k置于第x[k]列的合法性 (第k行,第x[k]列) 
    for(int j=1;jn){  //放置皇后个数超过n时候 ,可行解个数+1 
        for(int i=1;i<=n;i++)  
            y[i]=x[i];  
        return true;  
    }  
    else  
        for(int i=1;i<=n;i++)  
        {  
            x[t]=i;  //第t个皇后放在第i列 
            if(Place(t)&&Backtrack(t+1)) //可以place,就继续放下一个 
                return true;  
        }  
        return false;  
}  
  
bool Queen::QueensLV(int stopVegas)  
{//随机放置n个皇后拉斯维加斯算法  
    RandomNumber rnd;  
    int k=1;//随机数产生器  
    int count=1;  
    //1<=stopVegas<=n表示允许随机放置的皇后数  
    while((k<=stopVegas)&&(count>0))  
    {  
        count=0;  
        for(int i=1;i<=n;i++)  
        {  
            x[k]=i;  
            if(Place(k))  
                y[count++]=i;  //记录下所有可以放置的位置 
        }  
        if(count>0)  
            x[k++]=y[rnd.Random(count)];//如果能放置,随机选择一个可以放置的位置  
    }  
    return (count>0);//count>0表示放置成功  
}  
  
bool nQueen(int n,int sv)  
{  
    //与回溯法相结合的解n后问题的拉斯维加斯算法  
    Queen X;  
    //初始化X  
    X.n=n;  
    //X.sv=sv;
    int *p=new int[n+1];  //动态分配 
    int *q=new int[n+1];  
    for(int i=0;i<=n;i++)  //初始化数组 
    {  
        p[i]=0;  
        q[i]=0;  
    }  
    X.y=p;  
    X.x=q;  
    int stop=sv;  
    if(n>15)  
        stop=n-15;  
    bool found=false;  
    while(!X.QueensLV(stop));  
    //算法的回溯搜索部分  
    if(X.Backtrack(stop+1))  
    {  
        for(int i=1;i<=n;i++)  
            cout<

主函数的话,一个是输入皇后个数n和stop值用来比较不同n不同Stop的:

int main()    
{   
    int n,sv;
    cout<<"输入皇后个数n 和 stopVrgas值"<>n>>sv){
	
	   clock_t start,end,over;
       start=clock();
       end=clock();
       over=end-start;
       start=clock();
    
       if(!nQueen(n,sv))  
       {  
           cout<<"No Answer"<

运行起来是这样:

拉斯维加斯算法结合回溯法求解n后问题_第1张图片


另一个是用来测成功率的,由于成功率是很受样本大小影响的,样本越大越好,所以我干脆死循环,直接观察数据什么时候波动不大了就是最接近正确值的时候了:

int main()    
{   
    int n,sv,sumf=0,tmp=50000;
    double wl,sum=0.000;
    cout<<"输入皇后个数n 和 stopVrgas值"<

8皇后,stop=4书上的成功率是0.2618,但是我这边...

拉斯维加斯算法结合回溯法求解n后问题_第2张图片

???

差的有点多...而且已经这么多次循环了。

附上RandomNumber.h:

#include  
#include 
//#include "time.h" 
using namespace std;
 
//随机数类  
const unsigned long maxshort = 65536L;  
const unsigned long multiplier = 1194211693L;  
const unsigned long adder = 12345L;  
class RandomNumber  
{  
private:  
    //当前种子  
    unsigned long randSeed;  
public:  
    RandomNumber(unsigned long s=0);//构造函数,默认值0表示由系统自动产生种子  
    unsigned short Random(unsigned long n);//产生0:n-1之间的随机整数  
    double fRandom(void);//产生[0,1)之间的随机实数  
};  
  
RandomNumber::RandomNumber(unsigned long s)//产生种子  
{  
    if(s==0)  
        randSeed = time(0);//用系统时间产生种子  
    else  
        randSeed = s;//由用户提供种子  
}  
unsigned short RandomNumber::Random(unsigned long n)//产生0:n-1之间的随机整数  
{  
    randSeed=multiplier*randSeed+adder;  
    return (unsigned short)((randSeed>>16) % n);  
}  
double RandomNumber::fRandom(void)//产生[0,1)之间的随机实数  
{  
    return Random(maxshort) / double(maxshort);  
}   

你可能感兴趣的:(C++,算法分析)