拉斯维加斯算法结合回溯法求解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"<
运行起来是这样:
另一个是用来测成功率的,由于成功率是很受样本大小影响的,样本越大越好,所以我干脆死循环,直接观察数据什么时候波动不大了就是最接近正确值的时候了:
int main()
{
int n,sv,sumf=0,tmp=50000;
double wl,sum=0.000;
cout<<"输入皇后个数n 和 stopVrgas值"<
8皇后,stop=4书上的成功率是0.2618,但是我这边...
???
差的有点多...而且已经这么多次循环了。
附上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);
}