Las Vegas

拉斯维加斯算法是一种随机化算法。总之可以用来骗分。

以下类型的问题可以使用拉斯维加斯算法:

1. 寻找任意一个可行解。

2. 最优解占可行解集的比例较大。

3. 类似质因数分解的单一解问题,可以用此算法一步步得出解。

一般形式

while(!LasVegas());

N 皇后问题

目前公认的最优 N 皇后问题的解法是回溯(搜索)。复杂度约为 O(NN), 虽然当 N 大于 15 时搜索便开始罢工,但这样当然可以找到所有可行解。但是如果只要求找到任意一个解,回溯法就显得有些多余。

注意到 N 皇后问题的解并没有什么规律,皇后类似于随机摆放在棋盘上。所以可以利用 LasVegas 算法在前 k 行随机摆放皇后,后 (N-k) 行利用回溯完成。实践证明 1s 内可以在 N<=200 的范围内较为稳定地得出至少一个可行解。这比普通回溯法的效率高出了至少 2000 个数量级。%%%

/*
代码来源:《计算机算法设计与分析》
*/
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<ctime>
using namespace std;
class Queen
{
    friend bool nQueen(int);
private:
    bool Place(int k);              //测试皇后 K 置于 x[k] 列的合法性
    bool Backtrack(int t);          //解 n 后问题的回溯法
    bool QueenLV(int stopVegas);    //随机放置 n 个皇后的拉斯维加斯算法
    int n,*x,*y;
};
bool Queen::Place(int k)
{
    for(int j=1; j<k; j++)          //第 k 个皇后是否跟前面的皇后冲突
        if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))
            return false;
    return true;
}
bool Queen::Backtrack(int t)
{
    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;                 //t 皇后放在第 i 列
            if(Place(t)&&Backtrack(t+1))
                return true;
        }
    }
    return false;
}
bool Queen::QueenLV(int stopVegas)
{
                                    //随机放置 n 个皇后的拉斯维加斯算法

    int k=1;                        //随机数产生器
    int count=1;
                                    //1<=stopVagas=<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)                 //如果能放置,则在这么多个能放置第 k 个皇后的位置中选择一个位置
            x[k++]=y[rand()%count];
    }
    return(count>0);                //count>0 表示放置成功
}
bool nQueen(int n)
{
                                    //与回溯法相结合的接 n 后问题的拉斯维加斯算法
    Queen 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=5;
    if(n>15)
        stop=n-15;
    bool found=false;
    while(!X.QueenLV(stop));        //直到能放置
                                    //Backtreck 为算法的回溯搜索部分
    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()
{
    int n;
    cout<<"n:";
    cin>>n;
    if(!nQueen(n))
        cout<<"无解"<<endl;
    return 0;
}
分类: 文章

0 条评论

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用 * 标注