用回溯法及拉斯维加斯概率算法求解N皇后并比较其复杂性

n皇后问题
问题描述:
n皇后问题,即在n×n的棋盘上摆放n个皇后,使任意两个皇后都不能处于同一行、同一列或同一斜线上。
基本要求:
用回溯法及拉斯维加斯概率算法求解并比较复杂性。
测试数据:
要求至少测试四皇后、八皇后。

#include<iostream>
#include<math.h>
#include <ctime>
using namespace std;
int x[100],q[100];//q[i]=n表示回溯解,x表示概率解
int n,cnt = 0;
clock_t start1, finish1;
clock_t start2, finish2;
double totaltime1,totaltime2;

//回溯放置皇后时判断是否合法
bool find(int a[],int k)
{
    for(int i = 1;i < k;i++)
    {
        if(a[i] == a[k] || abs(k-i) == abs(a[k] - a[i]))
            return false;
    }
    return true;
}



bool Place(int x[],int k)
{
    for (int i = 0;i < k;i++)
        if(x[i] == x[k] || abs(i - k) == abs(x[i] - x[k]))
        {
            return true;
        }
    return false;
}

void print(int n)
{
    int i,j;
    cnt++;
    
    cout << "第 " << cnt << " 个解" << endl;
    
    for(i = 1;i <= n;i++)
        cout <<"(" <<  i << "," << q[i] << ")" << " ";//第i行放在第q[i]处。
    cout << endl;
    
    for(i = 1;i <= n;i++)        //行
    {
        for(j = 1;j <= n;j++)    //列
        {
            if(q[i] != j)
                printf("x ");
            else
                printf("Q ");
        }
        cout << endl;
    }
}

//回溯法求n皇后
void queen(int n){
    cnt = 0;
    for(int i = 0;i <= n;i++)//先将所有行的列数清零
    {
        q[i] = 0;
    }
    
    int k = 1;//k是行数
    while(k >= 1)
    {
        q[k] += 1;
        while(q[k] <= n )//未到达最后一列
        {
            if(find(q,k))
                break;
            else
                q[k]++;//该列不行向后推一个
        }
        if(k == n && q[k] <= n)//如果到最后一行,且最后列数正确
        {
            for(int i = 1;i <= n;i++)
            {
                cout << q[i] << " ";
                
            }
            cout << endl;
            print(n);//将皇后以棋盘式输出
        }
        else if(q[k] <= n)//如果还没有到达最后一列,继续下一列
        {
            k++;
        }
        else//回溯,因为到达最后一行,且列数遍历完,仍没有出结果
        {
            q[k] = 0;//让该行的列数重置为0
            k--;//继续回到上一行
            
        }
    }
}




//类,产生随机数
class RandomNumber{//类,这样才能保证不会出现产生的随机值都一样的情况。
public:
    RandomNumber(){
        srand(time(0));
    }
    int get(int begin = 0, int end = 1){//用这个函数可以得到随机值
        return rand()%(end-begin+1)+begin;
    }
};


bool Queen(int n) //拉斯维加斯概率求解
{
    RandomNumber arr[n + 1];
    
    int i,j,count=0;// //定义i,j,count. 其中count为试探次数
    for(i = 0;i < n;)// //其中 n为行数,for循环经过n次,每次代表在第n行中找到皇后所在的列
    {
            //为j赋值为一个随机数,此为拉斯维加斯概率算法的核心思想,通过随机性选择快速的引导算法
        j = arr[i + 1].get(1,n);//这样才可以保证每次的随机数都不一样,如果用j=rand()%n+1;不可以
        
        x[i]=j;  //将随机选取的j作为列向量参与接下来的运算
        count++;试探次数加一,用于确定N次运算后n列全部实验完毕
        if(!Place(x,i))   //这个if语句用于调用冲突子函数以确定是否发生冲突,即这个位置是否可以放置皇后
        {
            count=0;
            i++;
        }
        else if(count==n)   //位置冲突
        {
            return false;
      
        }
        
    }
    
    cout << "拉斯维加斯概率求解" << n << "皇后的一个解为" << endl;
    
    for(i=0;i<n;i++)//  //作为输出结果时的for循环
    {
       cout <<"(" <<  i + 1 << "," << x[i] << ")" << " ";
        
    }
    cout << endl;
    return true;
}



void runtime()
{
    totaltime1 = finish1 - start1;
    totaltime2 = finish2 - start2;
    cout << "回溯法求解"<< n << "皇后的运行时间为" << totaltime1 << "毫秒" << endl;
    cout << "拉斯维加斯概率算法求解 "<< n << "皇后的运行时间为" << totaltime2  << "毫秒"<< endl;
}

int choose()
{
    int ch;
    cout << endl << endl << endl;
    
    cout << "-----------------------n皇后问题---------------------" << endl;
    cout << "                请选择你要进行的操作                   " << endl;
    cout << "   1、回溯法求解              2、拉斯维加斯概率算法求解   " << endl;
    cout << "   3、查看两者运行时间比较              4、退出程序              " << endl;
    cout << "---------------------------------------------------" << endl;
    cin >> ch;
  
    return ch;
}





int main()
{
    int ch = choose();
  
    while(ch != 4)
    {
        
        switch (ch) {
            case 1:
                printf("请输入皇后的个数(n <= 32),n = :");
                cin >> n;
                start1 = clock();//开始计时
                queen(n);
                finish1 = clock();
                break;
                
            case 2:
                printf("请输入皇后的个数(n <= 32),n = :");
                cin >> n;
                start2 = clock();//开始计时
                cout << "正在重复测试,请等待······" << endl;
                while(!Queen(n))
                {
                }
                finish2 = clock();
                break;
            case 3:
                runtime();
                break;
            default:
                exit(0);
        }
      
        ch =  choose();
 
    }
    return 0;
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

算法的时间复杂度分析
对于回溯法来说,递归n行,每次循环n列,比较0~n - 1次
n * n * (n - 1) / 2 即O(n ^ 3),O(n * n * (n - 1) / 2) = O(n ^ 3)

对于拉斯维加斯概率算法
求出一组解的时候,仅需判断每次n行,比较0 ~ n - 1次
即 n * (n - 1) / 2 = O(n ^ 2)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Αиcíеиτеǎг

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值