求素数与环形公路堵车模型

本文所用解释器为python2.7

1 求素数方法的优化

(1)filter()的使用

filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。
filter(function, iterable)
function – 函数名(返回值必须是逻辑值),iterable – 可迭代对象。

def is_odd(n):
    return n % 2 == 1


tmplist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
newlist = list(tmplist)
print(newlist)

输出

[1, 3, 5, 7, 9]

从结果可以看到,filter的用法,就是将[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]中的元素,一个一个地代入到函数is_odd中,如果代进去为True,那么就保留,否则过滤掉,返回一个迭代器对象。

filter()的第一个参数,也可以为匿名函数

import math
tmplist = filter(lambda x:math.sqrt(x) % 1 == 0, range(1, 101))
newlist = list(tmplist)
print(newlist)

输出

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

(2)五种求素数方法的对比

先看方法三,便于理解

#!/usr/bin/python
# -*- coding:utf-8 -*-

import numpy as np
import math
from time import time
# 调用time模块来实现计时


def is_prime(x):
    return 0 not in [x % i for i in range(2, int(math.sqrt(x)) + 1)]


def is_prime3(x):
    flag = True
    for p in p_list2:
        if p > math.sqrt(x):
            break
        if x % p == 0:
            flag = False
            break
    if flag:
        p_list2.append(x)
    return flag


if __name__ == "__main__":
    a = 2
    b = 100000

    # 方法1:直接计算
    t = time()
    p = [p for p in range(a, b) if 0 not in [p % d for d in range(2, int(math.sqrt(p)) + 1)]]
    print time() - t
    print p

    # 方法2:利用filter
    t = time()
    p = filter(is_prime, range(a, b))
    print time() - t
    print p

    # 方法3:利用filter和lambda
    t = time()
    is_prime2 = (lambda x: 0 not in [x % i for i in range(2, int(math.sqrt(x)) + 1)])
    # [x % i for i in range(2, int(math.sqrt(x)) + 1)]表示x除以i得到的余数,i=2~sqrt(x)
    # 因为range是左闭右开,为了保证int(math.sqrt(x))能取到,因此需要加1
    # 如果x是素数,即除了1和本身以外没有其他约数,那么它除以2~sqrt(x)中的任何一个数,余数都不可能为0
    # 如果0不在[x % i for i in range(2, int(math.sqrt(x)) + 1)],
    # 说明x除以2~sqrt(x)中的任何一个数都除不尽,即x为素数

    p = filter(is_prime2, range(a, b))
    print time() - t
    print p

    # 方法4:定义
    t = time()
    p_list = []
    for i in range(2, b):
        flag = True
        for p in p_list:
            if p > math.sqrt(i):
                break
            if i % p == 0:
                flag = False
                break
        if flag:
            p_list.append(i)
    print time() - t
    print p_list

    # 方法5:定义和filter
    p_list2 = []
    t = time()
    filter(is_prime3, range(2, b))
    print time() - t
    print p_list2

    print '---------------------'
    a = 1180
    b = 1230
    a = 1600
    b = 1700
    p_list2 = []
    p = np.array(filter(is_prime3, range(2, b+1)))
    p = p[p >= a]
    print p
    p_rate = float(len(p)) / float(b-a+1)
    print '素数的概率:', p_rate, '\t',
    print '公正赔率:', 1/p_rate
    print '合数的概率:', 1-p_rate, '\t',
    print '公正赔率:', 1 / (1-p_rate)

输出
在这里插入图片描述
方法一耗时3.58秒,方法二1.92,方法三1.97,方法四0.36,方法五0.28
方法一使用列表生成器;方法二是将列表生成器转化判断函数,再套上了一filter方法,耗时明显比第一种方法耗时短;方法三是将方法二中的函数改成了匿名函数,消耗的时间与方法二相当;方法四直接按照定义去求,完全舍弃了列表生成器,用时大大缩短;方法五是对方法四进行了改进,套上了一层filter。
可以看到,使用filter能在一定程度上优化算法,但是优化的程度,远没有算法的改进效果好。

2 环形公路堵车模型

本节参考自博客:https://blog.csdn.net/weixin_42567027/article/details/107398651

(1)模型假设

路面上有n辆车,以不同的速度向前行驶, 模拟堵车问题。
有以下假设:
假设道路为环形封闭,即路面上的车不会少,也不会多,外面的车进不来,里面的也出不去。
某辆车的当前速度是v。
若前方可见范围内没车(即d>v),则它在下一秒的车速提高到v+1,直到达到规定的最高限速。
若前方有车,前车的距离为d,若d < v,则它下一秒的车速降低到d-1 ,若d=v,则速度不变。
每辆车会以概率p随机减速v-1。

#!usr/bin/env python
# -*- coding:utf-8 -*-
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt


# 对车辆的位移进行限制,当大于水平的公路长度时,则认为是该车进入了下一圈
def clip(x, path):
    for i in range(len(x)):
        if x[i] >= path:
            x[i] %= path


if __name__ == "__main__":

    # 文字转化
    mpl.rcParams['font.sans-serif'] = [u'SimHei']
    mpl.rcParams['axes.unicode_minus'] = False

    '''初始化定义'''
    path = 5000  # 环形公路的长度
    n = 100  # 公路中的车辆数目
    v0 = 50  # 车辆的初始速度
    p = 0.3  # 随机减速概率
    Times = 1000  # 模拟时间

    '''模拟车辆的位移和速度'''
    np.random.seed(0)

    # 模拟100辆车辆的位置
    # np.random.rand(n)返回的是n个0-1之间均匀分布的随机数
    x = np.random.rand(n) * path

    # 根据车辆的位置进行排序,原地替换
    x.sort()

    # 将所有车辆的初速度定义为50,并设为float类型数据
    v = np.tile([v0], n).astype(np.float)

    '''画布大小'''
    plt.figure(figsize=(8, 6))

    '''模拟在时间范围内的堵车情况'''
    for t in range(Times):
        # 根据第t时刻每辆车的位置绘图
        # x:车辆位置    [t]*n:时间,因为要保持横纵坐标的长度要相同
        plt.scatter(x, [t] * n, s=1, c='b', alpha=0.05) # alpha表示点的透明度

        '''计算每辆车第t时刻的速度和第t+1时刻的位置'''
        for i in range(n):

            # 计算前后车辆的距离
            # 对于最后一辆车,即 x[n-1],它的前一辆车是 x[n]
            # 但 x[n]会发生索引越界,因此使用 x[(i + 1) % n]代替 x[i+1]
            if x[(i + 1) % n] > x[i]:
                # 判断x[(i + 1) % n] > x[i],是为了判断前面的车是否已经进入下一圈
                # 因为假定没有超车的情况发生,因此前面的车,永远在前面
                d = x[(i + 1) % n] - x[i]
            else:
                d = x[(i + 1) % n] + path - x[i]

            '''根据与前车的距离调整速度'''
            if v[i] < d:
                # v[i] < d 表示前方可见范围没车
                # 若前方可见范围内没车,则它在下一秒的车速提高到v+1,直到达到规定的最高限速。
                # 同时,每辆车会以概率p随机减速v-1。
                if np.random.rand() > p:
                    v[i] += 1
                else:
                    v[i] -= 1
            elif v[i] > d:
                # 若前方有车,前车的距离为d,且d < v,则它下一秒的车速降低到d-1 。
                v[i] = d - 1

            # 还有一种情况,若v[i] = d,则第 i 辆车的速度不做调整

        # 限制速度,v<0,则将v定义为0;v>150,则将v定义为150
        v = v.clip(0, 150)

        # 车辆的位移在增加,车在往前开
        x += v

        # 调用clip,因为公路是环形封闭的,有些车已经进入下一圈了
        clip(x, path)

    '''限制坐标轴'''
    # 对x轴的坐标进行限制
    plt.xlim(0, path)
    # 对y轴坐标进行限制
    plt.ylim(0, Times)

    '''标签'''
    # 后面字符串以 Unicode 格式进行编码,一般用在中文字符串前面,
    # 防止因为源码储存格式问题,导致再次使用时出现乱码。
    # Python2.7需要在中文字符串前面加u,否则报错,Python3.X不需要
    plt.xlabel(u'车辆位置', fontsize=16)    # fontsize表示字体大小
    plt.ylabel(u'模拟时间', fontsize=16)
    plt.title(u'环形公路车辆堵车模拟', fontsize=20)

    '''自动调整子图参数,使之填充整个图像区域'''
    plt.tight_layout(pad=2)

    '''画图'''
    plt.show()

输出
在这里插入图片描述
如图所示,若以 p = 0.3 的概率减速,则会发生堵车,蓝色点密集的地方表示堵车

若以 p=0.15,则
在这里插入图片描述
可以看到,堵车仅仅发生最初时刻,后面的图像变得均匀,说明没有再发生堵车。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值