Las Vegas 与回溯组合法解八皇后问题

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

在这里插入图片描述

回溯法的原理用伪代码表示如下:

// 回溯法原理
QueenBacktrace{
	while(i < 8){
		检查当前行i,从当前列j开始向后找到一个可以放置的安全列号
		if 找到安全的列号{
			放置皇后,将列号入栈,进入下一行i++
			j = 0; // 下一行将从第0列开始搜索
		}
		else 找不到安全的列号 回溯{
			弹栈回到上一行i--
			移去放置的皇后,弹栈出来的j,j++继续向后搜索
		}
	}
}

然而当八皇后变成n皇后时,回溯法将爆炸性增长。这里将使用Las Vegas的概率算法与回溯法组合求解。
首先是贪心的Las Vegas算法原理:

  • 遍历n行,每一行尝试随机放置一个可以放置的位置,如可放置皇后的位置有{1,3,5,7},从其中随机挑一个

  • 每一次判断是否可以放置使用三种不冲突判断:

    • 无列冲突,任意两个行的列号不同
    • 无45°对角线冲突,即任意两个皇后(x1,y1) (x2,y2),x1-y1 != x2-y2
    • 无135°对角线冲突,即任意两个皇后(x1,y1) (x2,y2),x1+y1 != x2+y2
  • 在第stepVegas行开始,进入回溯法求解

如此是在前stepVegas行的皇后是概率的选取皇后位置,而第stepVegas行后是有回溯法确定的选择。

伪代码如下:

LVQueens(){ 
	col[8] // 存每行的皇后放置的列位置
	diag45 // 存已放置皇后的x-y值
	diag135 // 存以防止的皇后x+y值
	k = 0 // 行号
	repeat{
		nb = 0 // 计数器
		for i <- 0 to 8{ // 遍历8列
			if(i 不属于 col  and  (i-k) 不属于 diag45 and (i+k) 不属于diag135){
				nb += 1
				if random(1,nb)随机数从1~nb中选择出的值==1{
					j = i // 注意这里第一次可行的列号random一定选中了j = i
				}
			}
		}
		if(nb >0){ // 说明找到过可以放置的解
			# 此时第k行的皇后将放置在j位置上
            col.append(j)
            diag45.append(j-k)
            diag135.append(j+k)
            k += 1
		}
		if(nb == 0) return false // 说明没找到解
		if(k == stepVegas):  // 在第stepVegas行开始使用回溯法求解
            return QueenBacktrace(n, k, col, diag45, diag135, ans, count)
	}
}

回溯法和LV算法对比:

  • 回溯法是一定有精确解的
  • LV算法不一定有结果,可能是成功,也有概率失败
  • LV组合回溯算法也是有可能成功,有可能失败

为了衡量不同stepVegas从哪一行开始进行回溯效果最好,引入一个遍历节点消耗的概念:即放置一次皇后作为一次搜索的节点。显然LV算法中每一层只会放置一次皇后,而回溯法因为失败回溯会放置导致进入过错误的节点而节点数更多。

测试时候重复如repeat = 1000次,然后查看这1000次成功的概率为p,成功时候遍历节点的平均数为s,失败遍历的节点数平均为e,那么总的平均次数t为: t = s + ( 1 − p ) e p t = s+ \frac{(1-p)e}p t=s+p(1p)e

由以上的算法去测试结果如下

n = 8, stepVegas = 0 : p = 1.0 s = 114.0 e = 0 t = 114.0
n = 8, stepVegas = 1 : p = 1.0 s = 40.042 e = 0 t = 40.042
n = 8, stepVegas = 2 : p = 0.858 s = 22.884615384615383 e = 39.556338028169016 t = 29.43123543123543
n = 8, stepVegas = 3 : p = 0.518 s = 13.432432432432432 e = 15.236514522821576 t = 27.610038610038607
n = 8, stepVegas = 4 : p = 0.247 s = 10.48582995951417 e = 8.731739707835326 t = 37.10526315789474
n = 8, stepVegas = 5 : p = 0.157 s = 9.178343949044587 e = 7.290628706998814 t = 48.32484076433121
n = 8, stepVegas = 6 : p = 0.145 s = 9.027586206896551 e = 6.990643274853801 t = 50.248275862068965
n = 8, stepVegas = 7 : p = 0.141 s = 9.0 e = 6.933643771827707 t = 51.241134751773046
n = 8, stepVegas = 8 : p = 0.127 s = 9.0 e = 6.953035509736541 t = 56.79527559055118
n = 8, bestStepVegas = 3

所以看到当bestStepVegas =3时候效果最好,遍历的节点数最小,比单纯回溯法114次遍历节点数降低到27.6。

这里给出对于n皇后的组合算法求解n=8~20的对比,如下代码:

import random
random.seed(0)
def QueenBacktrace(n, k, col, diag45, diag135, ans, count):
    """
    从第k行开始使用回溯法求n皇后
    """
    i = k # 行
    j = 0 # 列
    while(i < n and i >= k):
        # 找到当前行i的一个安全列,除非找不到了
        if(j < n):
            if (j not in col) and ((j-i) not in diag45) and ((j+i) not in diag135):
                count += 1
                # 找到了安全列,放置皇后,入栈,进入下一行
                ans[i] = j # 入栈结果
                col.append(j)
                diag45.append(j-i)
                diag135.append(j+i)
                i += 1 # 下一行
                j = 0
            else:
                j += 1
        # 找不到安全的列号,弹栈回溯 
        else:
            i -= 1 
            j = ans[i] + 1
            col.pop()
            diag135.pop()
            diag45.pop()
    if(i == n):
        return True,ans,count
    else:
        return False,ans,count


    # for j in range(n): 
    #     # 找到起始第k行的安全的行号进入回溯法
    #     if (j not in col) and ((j-k+1) not in diag45) and ((j+k+1) not in diag135):
    #         for i in range(k+1, n): 


def QueensLV(n, stepVegas):
    """ LV 混合 回溯的Queen算法 """
    count = 1 # 计数通过的节点数
    col = [] # 已使用列集合
    diag45 = [] # 45度对角线冲突集合
    diag135 = [] # 135度对角线冲突集合
    ans = [0 for i in range(n)] # 皇后放在第index行的第ans[index]列
    k = 0 # 行号
    j = 0 # 选择的安全行号
    while(True):
        nb = 0 # 计数器
        if(k == stepVegas):
            break
        for i in range(n):
            # 循环随机找一个开放的位置
            if (i not in col) and ((i-k) not in diag45) and ((i+k) not in diag135):
                nb += 1
                if(random.randint(1,nb) == 1):
                    j = i
        if(nb > 0):
            # 此时第k+1的皇后将放置在j位置上
            count+=1
            ans[k] = j
            col.append(j)
            diag45.append(j-k)
            diag135.append(j+k)
            k += 1
        if(nb == 0):
            return (False,ans,count)
        
    # 回溯法继续执行
    return QueenBacktrace(n, k, col, diag45, diag135, ans, count)

repeat = 1000
for i in range(8,21):
    minT = 100000000000 # 找到最小的node次数
    bestStepVegas = 0
    for stepVegas in range(0,i+1):
        s = 0
        s_count = 0
        e = 0
        e_count = 0
        for j in range(repeat):
            flag,ans,count = QueensLV(i,stepVegas)
            if(flag):
                s += count
                s_count += 1
            else:
                e += count
                e_count += 1
        if(s_count == 0):
            s = 0
        else:
            s = 1.0*s/s_count
        if(e_count == 0):
            e = 0
        else:
            e = 1.0*e/e_count
        p = s_count/repeat
        t = s + e*e_count/s_count
        print("n = "+str(i)+", stepVegas = "+str(stepVegas)+ " : p = "+str(p) +" s = "+str(s)+ " e = "+str(e)+" t = "+str(t))
        if(minT > t):
            minT = t
            bestStepVegas = stepVegas
    print("n = "+str(i)+", bestStepVegas = "+str(bestStepVegas) + "\n")
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要在DevStack上安装OpenStack Queens版本,您可以按照以下步骤进行操作: 1. 首先,确保您的系统满足以下要求: - Ubuntu 16.04 LTS操作系统(推荐) - 至少8GB的RAM和2个CPU核心 - 至少40GB的硬盘空间 2. 下载DevStack安装脚本并切换到下载目录: ```shell $ git clone https://opendev.org/openstack/devstack.git $ cd devstack ``` 3. 创建一个名为`local.conf`的新文件,并将以下内容复制到文件中: ```shell [[local|localrc]] HOST_IP=<your_host_ip> SERVICE_HOST=<your_service_host_ip> DATABASE_PASSWORD=<your_database_password> RABBIT_PASSWORD=<your_rabbitmq_password> ADMIN_PASSWORD=<your_admin_password> ``` 将`<your_host_ip>`替换为主机的IP地址,`<your_service_host_ip>`替换为服务主机的IP地址,`<your_database_password>`替换为数据库密码,`<your_rabbitmq_password>`替换为RabbitMQ密码,`<your_admin_password>`替换为管理员密码。 4. 运行安装脚本: ```shell $ ./stack.sh ``` 5. 安装过程可能需要一些时间,请耐心等待。一旦安装完成,您将在终端上看到"DevStack successfully installed"的消息。 6. 安装完成后,您可以通过浏览器访问`http://<your_host_ip>/dashboard`来访问OpenStack Horizon仪表板。使用管理员帐户名`admin`和先前在`local.conf`中设置的管理员密码进行登录。 请注意,这只是一个简单的安装过程示例,您可能需要根据自己的环境和需求进行一些自定义配置。有关更详细的安装说明,请参阅OpenStack官方文档。 祝您安装成功!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AlwaysDayOne

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

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

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

打赏作者

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

抵扣说明:

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

余额充值