n皇后的拉斯维加斯回溯算法

<1>、拉斯维加斯概念:

     拉斯维加斯算法不会得到不正确的解。一旦用拉斯维加斯算法找到一个解,这个解就一定是正确解。但有时用拉斯维加斯算法会找不到解。拉斯维加斯算法找到正确解的概率随着它所用的计算时间的增加而提高。对于所求解的任一实例,用同一拉斯维加斯算法反复对该例求解足够多次,可使求解失效的概率任意小。

     通常用一个bool类型的函数表示拉斯维加斯算法,拉斯维加斯算法的典型调用形式为bool success=LV(x,y);当success值为false时,算法未能找到问题的解。此时可对同一实例再次独立地调用相同的算法。

<2>、算法思路:

     将拉斯维加斯与回溯法相结合求解n皇后问题,先在棋盘的若干行中随机地放置皇后,然后在后继行中用回溯法继续放置,直到找到一个解或宣告失败。随机放置的皇后越多,后继回溯搜索所需的时间就越少,但失败的概率也就越大。

     下表给出用拉斯维加斯回溯算法解八皇后问题时,对于不同的stopVegas值,算法成功的概率p,一次成功搜索访问的结点数平均值s,一次不成功搜索访问的节点数平均值e,以及反复调用算法使得最终找到一个解所访问的节点数的平均值t=s+(1-p)e/p。


     其中stopVegas=0相应于完全使用回溯法的情形,由表可以看出来,当n=8时,取stopVegas=2时,效率很高。故本算法取stopVegas=2

<3>算法程序:

#include <iostream>  
#include <cmath>   
#include "RandomNumber.h"   
using namespace std;  

class Queen
{
    friend bool nQueen(int);
private:
    bool Place(int k);//测试皇后k置于第x[k]列的合法性
    bool Backtrack(int t);//解n后问题的回溯法
    bool QueensLV(int stopVegas);//随机放置n个皇后拉斯维加斯算法
    int n,*x,*y;
};

bool Queen::Place(int k)
{//测试皇后k置于第x[k]列的合法性
    for(int j=1;j<k;j++)
        if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))
            return false;
    return true;
}

bool Queen::Backtrack(int t)
{//解n后问题的回溯法
    if(t>n){
        for(int i=1;i<=n;i++)
            y[i]=x[i];
        return true;
    }
    else
        for(int i=1;i<=n;i++)
        {
            x[t]=i;
            if(Place(t)&&Backtrack(t+1))
                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)
{
    //与回溯法相结合的解n后问题的拉斯维加斯算法
    Queen X;
    //初始化X
    X.n=n;
    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=2;
    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<<p[i]<<" ";
        found=true;
    }
    cout<<endl;
    delete []p;
    delete []q;
    return found;
}

int main()  
{   
    if(!nQueen(8))
    {
        cout<<"搜索不成功!!"<<endl;
    }
    system("pause");
    return 0;
}  
 其中随机生成头文件RandomNumber.h:

#include <ctime>

//随机数类
const unsigned long maxshort = 65536L;
const unsigned long multiplier = 1194211693L;
const unsigned long adder = 12345L;
class RandomNumber
{
private:
    //当前种子
    unsigned long randSeed;
public:
    RandonNumber(unsigned long s=0);//构造函数,默认值0表示由系统自动产生种子
    unsigned short Random(unsigned long n);//产生0:n-1之间的随机整数
    double fRandom(void);//产生[0,1)之间的随机实数
};

RandomNumber::RandonNumber(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);
} 




拉斯维加斯算法(LV Algorithm)用于求解N皇后问题时,采用了一种折衷的方法。首先,通过随机放置一些皇后的位置,这利用了消极的特性(即使失败也不会导致整个搜索过程终止)。如果随机尝试失败,算法回溯到先前的状态,但这不是传统的回溯法,因为可能会有不止一步的回退,而是选择继续寻找其他可能的解决方案。 具体实现时,你可以结合随机策略和回溯算法步骤如下: 1. **随机放置**:从棋盘的第一列开始,随机选择一个合法的位置放置第一个皇后。 2. **递归尝试**:对剩余的列重复此过程,每次尝试都在上一个皇后所在列的右侧放置下一个皇后,直到最后一列。 3. **冲突检测**:检查新放置的皇后是否与之前放置的皇后造成冲突(在同一行、同一直线),若冲突则回溯。 4. **成功条件**:当放置完所有皇后且无冲突时,返回解;若无法继续,随机重新开始尝试。 以下是一个简单的Python示例,展示如何使用这种方法解决八皇后问题[^2]: ```python def solve_n_queens(n): def place_queen(row, board): if row == n: return True for col in range(n): if not conflict(board, row, col): board[row][col] = "Q" if place_queen(row + 1, board): return True board[row][col] = "." return False def conflict(board, row, col): for i in range(row): if board[i][col] == "Q" or \ abs(i - row) == abs(col - board[i][col].index("Q")): return True return False board = [["."] * n for _ in range(n)] start_time = time.time() solution = place_queen(0, board) end_time = time.time() if solution: print_board(board) print(f"Took {end_time - start_time:.2f} seconds to find a solution.") else: print("No solution found.") # 使用拉斯维加斯算法求解8皇后问题 solve_n_queens(8) ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值