2021华为软挑赛题_思路分析——实时更新,做多少更多少(七)

2021华为软挑赛题_思路分析——实时更新,做多少更多少(七)



本专栏食用建议

  • 随着文章越更越多,本专栏的内容到底该如何食用,笔者在此做出如下建议,望能为参赛的诸位节省宝贵的时间和精力:
  • 新朋友可以先阅读第七篇,看到结果后再重新阅览其他文章,此文介绍:training-1跑出了4533492832的结果,training-2跑出了5316109914,此结果是在无迁移无删除的情况下得到的,附源码
  • 本专栏内容第一篇为思路的初步探索,适合没有多少思路或者对赛题把握比较模糊的朋友。当然,在赛程后期,有朋友已经做完提交想要在温故一遍赛题的话,亦可回顾此文
  • 至于第二篇文章,确实建议大家可以详细浏览,包含着鄙人对于此题的主要思路,至少相比于同类文章,个人认为此想法是最为可能落地的一种(暂不谈算法效率)。
  • 接下来的三篇文章(后面大致如此),主要是对第二篇文章的代码实现,可尽可能地去读最新的代码,毕竟,写着写着发现之前问题的事情也不是头一次发生,望诸位见谅~
  • 至于第六篇文章,鄙人决定对诸位朋友所提的问题加以总结(会不断扩充),在此篇做统一的解释。当然,这里的解释一定不能完全的解决大家的问题,但,鄙人自当尽力,诸位也各取所需~
  • 当然,以上不过是鄙人的小小建议,若有朋友希望能够完全的去理解鄙人解题的全部心路历程,逐篇阅读亦未尝不可~

3月19日更新


1.这里绝对有你想要看到的——此结果非标准输出-4533492832

  • 今天这里也不说废话了,相信一直关注鄙人更新的朋友或多或少都有些收获,但同时也存在一些疑惑,毕竟,这个思路到底如何?最终是否能行的通?跑出的结果能否达到要求?这些在没有出今日的结果前鄙人也不敢为诸位打包票。但今日,热乎的结果已出,希望此结果能够让追更的朋友觉得值得,让正在观看文章的你也能觉得此番浏览,没有白白浪费时间。如此鄙人心足矣~
  • Ps:以下代码并非赛方要求的输出,仅做为朋友分析、参考、学习。

1. 结果分析与优化方向建议

结果1
结果2

  • 如上两图,上方为training-1跑出的结果总花销为4533492832,纯硬件花销2961011870,下方为training-2跑的结果总花销为5316109914,纯硬件花销3477108554。当然,这个结果是在已经粗略的计入了每日的服务器成本,同时没有处理删除和迁移,在每台服务器都存在一定资源空隙的情况下产生的结果。
  • 对数据粗略的分析,training-1总花销与纯硬件花销差了约15亿,training-2也差不多差了20亿,因此不难看出,在最初考虑性价比的定义时,极有必要将服务器每日成本考虑进来,这将对结果的优化起到极大的作用。
  • 同时,对于此购买分配方案,进一步的优化方向可采取将每日请求数据依照核内比继续细分(之前采用平均核内比)。当然,如此对于迁移方法将提出更大的要求。
  • training-1比training-2在请求天数上多了200天(但实际每天的请求数2少于1,且2中删除请求明显增多),最终花销差了8亿,其中,硬件花销上差了5亿,每日成本花销差了3亿。但如果细心观察过数据的朋友,可能不难看出,2中数据服务器硬件开销均价高于1中数据,简单总结,这5亿中能优化的主要方向,在于处理删除请求与合理的迁移,毕竟基础的购买分配思路在想要提升难度会不小。
  • 站在如今榜首跑到10亿左右的结果面前,这样一个基础的算法跑出的结果的确不够看。但是毕竟本人提供的思路走基础路线,同时,优化后的结果,跑到10几亿也是很有希望的(有心的朋友可计算一下当前分配结果下产生的资源空隙)。
  • 接下来,鄙人的博客将会不定期的更新此代码的优化路线,望诸位朋友多多支持~

2. 源码

  • 此代码解决了单节点服务器分配、购买的算法,并且可以输出相应的结果,仅供大家学习~
# 代码解决2021华为软件挑战赛中的数据输入问题
# 所有注释为了便于说明
# 以training-1.txt中的数据为例
# !!!*****!!! 为昨日代码的出错点
# 技艺不精,私事繁忙,照顾不周,多担待!

# 导入numpy库
import numpy

# 服务器类
class Host:
    hostType = ''           # 服务器类型
    hostCpuNum = 1          # 服务器CPU数
    hostMemSize = 1         # 服务器内存容量
    hostHardWareCost = 1    # 服务器硬件开销
    hostDayCost = 1         # 服务器每日开销
    hostXingJiaBi = 1       # 服务器性价比:(硬件开销*(核数/核数+内存容量)/核数) + (硬件开销*(内存容量/核数+内存容量)/内存容量)
    hostCoreMemBi = 1       # 服务器核内比:核数/内存容量
    cpuNumDValue = 1        # 凑数后cpuNum的差值
    memSizeDValue = 1       # 凑数后memSize的差值

    # 临时存储由凑数过程产生的每一台服务器中所添加的虚拟机相关信息的列表
    def __init__(self):
        self.addVmList = []     # 存储虚拟机的相关信息
                                # 列表中依次为requireType, vmType, vmId,
        #                       # vmCpuNum, vmMemSize, vmDoubleOrNot, vmCoreMemBi

    # 计算性价比
    # !!!认真观察的道友应该能发现,此处公式与昨日略有不同,但与昨日数值结果相同,可自己细品,理解鄙人定义的性价比的意义!!!
    def xingJiaBi(self):
        self.hostXingJiaBi = ((self.hostHardWareCost * self.hostCpuNum / (self.hostCpuNum + self.hostMemSize)) / self.hostCpuNum) + ((self.hostHardWareCost * self.hostMemSize / (self.hostCpuNum + self.hostMemSize)) / self.hostMemSize)

    # 计算核内比
    def coreMemBi(self):
        self.hostCoreMemBi = self.hostCpuNum / self.hostMemSize

# 虚拟机类
class Vm:
    vmType = ''
    vmCpuNum = 1
    vmMemSize = 1
    vmDoubleOrNot = 1
    vmCoreMemBi = 1

    # 计算核内比
    def coreMemBi(self):
        self.vmCoreMemBi = self.vmCpuNum / self.vmMemSize

# 每日请求列表类——输入数据时使用
class DayRequire:
    requireNum = 0
    requireType = ''
    vmType = ''
    vmId = ''
    averageDoubleCoreMemBi = ''
    averageSingleCoreMemBi = ''

    # !!!昨日出错重点,以前一直没发现,pyhton类中定义的列表是全局变量!!!
    # 解决方法:通过初始化方法,将列表定义为self的局部变量
    def __init__(self):
        self.addRequireList = []
        self.addRequireList_Double = []     # 列表中为一日请求中的双节点请求
                                            # 且按照averageDoubleCoreMemBi是否大于1
                                            # 按照cpuNum升序(或者memSize升序排序)
                                            # 列表中依次为requireType, vmType, vmId,
                                            # vmCpuNum, vmMemSize, vmDoubleOrNot, vmCoreMemBi
        self.addRequireList_Single = []
        self.delRequireList = []

    # !!!增加了两个为列表赋值的函数,只为美化代码!!!
    def addRequireListAppend(self):
        self.addRequireList.append([self.requireType, self.vmType, self.vmId])

    def delRequireListAppend(self):
        self.delRequireList.append([self.requireType, self.vmId])

    # 计算每日add请求平均核内比
    def averageCoreMemBi(self):
        tempList = [require[6] for require in self.addRequireList_Double]
        self.averageDoubleCoreMemBi = numpy.mean(tempList)
        tempList = [require[6] for require in self.addRequireList_Single]
        self.averageSingleCoreMemBi = numpy.mean(tempList)

# 输出类
class OutPut:
    buyHostNumAll = 1          # 购买服务器总数量
    buyHostType = ''           # 购买服务器类型
    buyHostNumOne = 1          # 购买单款服务器的数量

    migrationNumAll = 1        # 总的迁移次数
    migrationVmId = ''         # 迁移虚拟机Id
    migrationHostId = ''       # 迁移目的地的服务器Id
    migrationHostPoint = ''    # 迁移目的地的服务器节点

    vmHostId = ''              # 虚拟机分配到的服务器的Id
    vmHostPoint = 'A'          # 虚拟机分配到的服务器的节点

    def __init__(self):
        self.oneDayBuyHostTempList = []         # 暂存购买服务器的相关信息
        self.oneDayBuyHostList = []             # 一日购买服务器列表
                                                # 每一项为(buyHostType, buyHostNumOne)
        self.oneDayMigrationList = []           # 一日迁移列表
                                                # 每一项为(migrationVmId, migrationHostId, migrationHostPoint)
                                                # 或者(migrationVmId, migrationHostId)
        self.oneDayDistributionList = []        # 一日分配列表
                                                # 每一项为(vmHostId, vmHostPoint)
                                                # 或者(vmHostId)


# 标准输出
# (purchase, 2)
# (NV603, 1)
# (NV604, 1)
# (migration, 0)
# (0, A)
# (0, B)

# def standardPrint():



# 一次性读入全部文件
def readTxt(filename):
    try:
        f = open(filename, "r")
        line = f.read()
        return line
    finally:
        f.close()

#按核内比分类
def classifyByCoreMemBi(hostListAll):
    # 核内比大于一的分一类,小于一的分一类
    hostCoreMemBiList = [host.hostCoreMemBi for host in hostListAll]
    hostCoreMemBiList = numpy.array(hostCoreMemBiList)
    posCoreMemBiBig = numpy.argwhere(hostCoreMemBiList > 1)
    # print(posCoreMemBiBig)
    hostCoreMemBiBigList = [hostListAll[n[0]] for n in posCoreMemBiBig]
    posCoreMemBiSmall = numpy.argwhere(hostCoreMemBiList <= 1)
    hostCoreMemBiSmallList = [hostListAll[n[0]] for n in posCoreMemBiSmall]

    return hostCoreMemBiBigList, hostCoreMemBiSmallList

def sortByAverageCoreMemBi(dayList):
    # 处理Double
    if dayList.averageDoubleCoreMemBi >= 1:
        # 取出vmCpuNum存成列表
        vmCpuNumTempList = [addRequireList_Double[3] for addRequireList_Double in dayList.addRequireList_Double]
        vmCpuNumTempList = numpy.array(vmCpuNumTempList)
        # 按照vmCpuNum升序排序
        posVmCpuNumList = numpy.argsort(vmCpuNumTempList)
        dayList.addRequireList_Double = [dayList.addRequireList_Double[n] for n in posVmCpuNumList]

    else:
        # 取出vmMemSize存成列表
        vmMemSizeTempList = [addRequireList_Double[4] for addRequireList_Double in dayList.addRequireList_Double]
        vmMemSizeTempList = numpy.array(vmMemSizeTempList)
        # 按照vmMemSize升序排序
        posVmMemSizeList = numpy.argsort(vmMemSizeTempList)
        dayList.addRequireList_Double = [dayList.addRequireList_Double[n] for n in posVmMemSizeList]
    # 处理Single
    if dayList.averageSingleCoreMemBi >= 1:
        # 取出vmCpuNum存成列表
        vmCpuNumTempList = [addRequireList_Single[3] for addRequireList_Single in dayList.addRequireList_Single]
        vmCpuNumTempList = numpy.array(vmCpuNumTempList)
        # 按照vmCpuNum升序排序
        posVmCpuNumList = numpy.argsort(vmCpuNumTempList)
        dayList.addRequireList_Single = [dayList.addRequireList_Single[n] for n in posVmCpuNumList]
    else:
        # 取出vmMemSize存成列表
        vmMemSizeTempList = [addRequireList_Single[4] for addRequireList_Single in dayList.addRequireList_Single]
        vmMemSizeTempList = numpy.array(vmMemSizeTempList)
        # 按照vmMemSize升序排序
        posVmMemSizeList = numpy.argsort(vmMemSizeTempList)
        dayList.addRequireList_Single = [dayList.addRequireList_Single[n] for n in posVmMemSizeList]
    # print(dayList.addRequireList_Double)

# 数据预处理
def dataPraparation(hostListAll, vmListAll, dayListAll):
    # 将服务器列表按照性价比排序
    # 取出hostXingJiaBi单做一个列表
    hostXingJiaBiList = [host.hostXingJiaBi for host in hostListAll]
    # print(hostXingJiaBiList)
    # 调用numpy.argsort函数排序返回下标
    hostXingJiaBiList = numpy.array(hostXingJiaBiList)
    # print(hostXingJiaBiList)
    posHostXingJiaBiList = numpy.argsort(hostXingJiaBiList)
    # print(pos)
    hostListAll = [hostListAll[n] for n in posHostXingJiaBiList]

    # 服务器按照核内比分类
    [hostCoreMemBiBigList, hostCoreMemBiSmallList] = classifyByCoreMemBi(hostListAll)

    # 匹配每日请求中虚拟机型号与虚拟机总表中的虚拟机型号
    # 增添addRequireList的数据
    vmTypeListAll = [vm.vmType for vm in vmListAll]
    vmTypeListAll = numpy.array(vmTypeListAll)
    # 获取全部add请求的列表
    addRequireListAll = [day.addRequireList for day in dayListAll]
    # print(addRequireListAll)
    # 为dayListAll中的addRequireList增添vmCpuNum,vmMemSize,vmDoubleOrNot,vmCoreMemBi
    for i in range(len(dayListAll)):
        # 取出一日的请求
        vmTypeOneDayList = [oneRequire[1] for oneRequire in addRequireListAll[i]]
        # print(vmTypeOneDayList)
        posVmTypeListAll = [numpy.argwhere(vmTypeListAll == vmTypeOne) for vmTypeOne in vmTypeOneDayList]
        # print(posVmTypeListAll[0][0][0])
        # 为每一天的一项add请求增添vmCpuNum,vmMemSize,vmDoubleOrNot,vmCoreMemBi元素
        # !!!为了保证符合标准输出,此处加上每条add请求的原始位置!!!
        for j in range(len(posVmTypeListAll)):
            # print(posVmTypeListAll[j][0][0])
            temp = [vmListAll[posVmTypeListAll[j][0][0]].vmCpuNum,
                    vmListAll[posVmTypeListAll[j][0][0]].vmMemSize,
                    vmListAll[posVmTypeListAll[j][0][0]].vmDoubleOrNot,
                    vmListAll[posVmTypeListAll[j][0][0]].vmCoreMemBi,
                    j]
            # print(temp)
            # print(dayListAll[i].addRequireList[0])
            dayListAll[i].addRequireList[j].extend(temp)
            # print(dayListAll[0].addRequireList[j])

            # 将addRequireList按单双节点分类
            if dayListAll[i].addRequireList[j][5] == 1:
                dayListAll[i].addRequireList_Double.append(dayListAll[i].addRequireList[j])
            else:
                dayListAll[i].addRequireList_Single.append(dayListAll[i].addRequireList[j])
        dayListAll[i].averageCoreMemBi()

        # 判断单、双节点请求的平均核内比是否大于1
        # 若大于1,将两个列表按照vmCpuNum(核数)将vm升序排列
        # 否则,按照vmMemSize(内存容量)升序排列
        sortByAverageCoreMemBi(dayListAll[i])
    # print(hostCoreMemBiBigList)
    return hostCoreMemBiBigList, hostCoreMemBiSmallList


# 处理双节点请求,购买服务器
def doubleShopping(oneDayOutput, dayListOne, hostCoreMemBiBigSmallList):
    # while判断请求列表是否为空
    while len(dayListOne.addRequireList_Double) != 0:
        # 初始化
        cpuNumDValueTempList = [0 for k in range(len(hostCoreMemBiBigSmallList))]
        memSizeDValueTempList = [0 for k in range(len(hostCoreMemBiBigSmallList))]
        posTempList = [0 for k in range(len(hostCoreMemBiBigSmallList))]
        # 此for循环每执行一次,便将一日的请求处理一部分,同时得出一台需要购买的服务器
        for k, hostCoreMemBiBigSmall in enumerate(hostCoreMemBiBigSmallList):
            # 用于累加
            sumVmCpuNum = 0
            sumVmMemSize = 0
            pos = 0
            # 取出vmCpuNum,便于累加
            vmCpuNumTempList = [oneRequire[3] for oneRequire in dayListOne.addRequireList_Double]
            vmMemSizeTempList = [oneRequire[4] for oneRequire in dayListOne.addRequireList_Double]
            for j in range(len(vmCpuNumTempList)):
                if hostCoreMemBiBigSmall.hostCpuNum >= sumVmCpuNum and hostCoreMemBiBigSmall.hostMemSize >= sumVmMemSize:
                    sumVmCpuNum += vmCpuNumTempList[j]
                    sumVmMemSize += vmMemSizeTempList[j]
                    hostCoreMemBiBigSmall.addVmList.append(dayListOne.addRequireList_Double[j])
                else:
                    pos = j - 1
                    sumVmCpuNum -= vmCpuNumTempList[pos]
                    sumVmMemSize -= vmMemSizeTempList[pos]
                    hostCoreMemBiBigSmall.cpuNumDValue = hostCoreMemBiBigSmall.hostCpuNum - sumVmCpuNum
                    hostCoreMemBiBigSmall.memSizeDValue = hostCoreMemBiBigSmall.hostMemSize - sumVmMemSize
                    break

            # print(hostCoreMemBiBig.memSizeDValue)

            # 取出差值存入列表
            cpuNumDValueTempList[k] = hostCoreMemBiBigSmall.cpuNumDValue
            memSizeDValueTempList[k] = hostCoreMemBiBigSmall.memSizeDValue
            posTempList[k] = pos

        # 找到cpuNum差值最小的服务器,此时只考虑cpuNum
        if dayListOne.averageDoubleCoreMemBi >= 1:
            posCpuMin = cpuNumDValueTempList.index(min(cpuNumDValueTempList))
            oneDayOutput.oneDayBuyHostTempList.append(hostCoreMemBiBigSmallList[posCpuMin])
            # 将原列表中已经添加的相关add请求,去除已经添加过的部分
            # 感谢resetmefun朋友的纠正!
            # 鄙人学艺不精,常有出错之时,代码有错之处望朋友们不吝赐教!
            dayListOne.addRequireList_Double = dayListOne.addRequireList_Double[(posTempList[posCpuMin] + 1):]
        # 找到memSize差值最小的服务器,此时只考虑memSize
        else:
            posMemMin = memSizeDValueTempList.index(min(memSizeDValueTempList))
            oneDayOutput.oneDayBuyHostTempList.append(hostCoreMemBiBigSmallList[posMemMin])
            # 将原列表中已经添加的相关add请求,去除已经添加过的部分
            dayListOne.addRequireList_Double = dayListOne.addRequireList_Double[(posTempList[posMemMin] + 1):]


# 处理单节点请求,购买服务器
# 与双节点不同之处在于需要将服务器劈成两半考虑
# 实现方法很多,鄙人采取一种讨巧的方式
# 诸位亦可各自发挥
def singleShopping(oneDayOutput, dayListOne, hostCoreMemBiBigSmallList):
    # while判断请求列表是否为空
    while len(dayListOne.addRequireList_Single) != 0:
        # 初始化
        cpuNumDValueTempList = [0 for k in range(len(hostCoreMemBiBigSmallList))]
        cpuNumDValueTempList_A = [0 for k in range(len(hostCoreMemBiBigSmallList))]
        cpuNumDValueTempList_B = [0 for k in range(len(hostCoreMemBiBigSmallList))]
        memSizeDValueTempList = [0 for k in range(len(hostCoreMemBiBigSmallList))]
        memSizeDValueTempList_A = [0 for k in range(len(hostCoreMemBiBigSmallList))]
        memSizeDValueTempList_B = [0 for k in range(len(hostCoreMemBiBigSmallList))]
        posTempList = [0 for k in range(len(hostCoreMemBiBigSmallList))]
        # 用于判断此时凑的是服务器的A or B节点
        # 当flag为0时表示此轮请求正在凑A节点服务器,存储此时的差值
        # 当flag为1时表示此轮请求正在凑B节点服务器,存储此时的差值
        # 最后判断差值加和最小的服务器为需要购买的服务器
        flag = 0

        # 此for循环每执行一次,便将一日的请求处理一部分,同时凑出半台服务器资源
        for k, hostCoreMemBiBigSmall in enumerate(hostCoreMemBiBigSmallList):
            # 用于累加
            sumVmCpuNum = 0
            sumVmMemSize = 0
            pos = 0
            # 取出vmCpuNum,便于累加
            vmCpuNumTempList = [oneRequire[3] for oneRequire in dayListOne.addRequireList_Single]
            vmMemSizeTempList = [oneRequire[4] for oneRequire in dayListOne.addRequireList_Single]
            for j in range(len(vmCpuNumTempList)):
                if (hostCoreMemBiBigSmall.hostCpuNum / 2) >= sumVmCpuNum and (hostCoreMemBiBigSmall.hostMemSize / 2) >= sumVmMemSize:
                    sumVmCpuNum += vmCpuNumTempList[j]
                    sumVmMemSize += vmMemSizeTempList[j]
                    hostCoreMemBiBigSmall.addVmList.append(dayListOne.addRequireList_Single[j])
                else:
                    pos = j - 1
                    sumVmCpuNum -= vmCpuNumTempList[pos]
                    sumVmMemSize -= vmMemSizeTempList[pos]
                    hostCoreMemBiBigSmall.cpuNumDValue = hostCoreMemBiBigSmall.hostCpuNum - sumVmCpuNum
                    hostCoreMemBiBigSmall.memSizeDValue = hostCoreMemBiBigSmall.hostMemSize - sumVmMemSize
                    break
            # 存储每次break的位置
            posTempList[k] = pos
            if flag == 0:
                # 取出差值存入A列表
                cpuNumDValueTempList_A[k] = hostCoreMemBiBigSmall.cpuNumDValue
                memSizeDValueTempList_A[k] = hostCoreMemBiBigSmall.memSizeDValue
                flag = 1
            else:
                # 取出差值存入B列表
                cpuNumDValueTempList_B[k] = hostCoreMemBiBigSmall.cpuNumDValue
                memSizeDValueTempList_B[k] = hostCoreMemBiBigSmall.memSizeDValue
                cpuNumDValueTempList[k] = cpuNumDValueTempList_A[k] + cpuNumDValueTempList_B[k]

        # 找到cpuNum差值最小的服务器,此时只考虑cpuNum
        if dayListOne.averageSingleCoreMemBi >= 1 and flag == 1:
            posCpuMin = cpuNumDValueTempList.index(min(cpuNumDValueTempList))
            oneDayOutput.oneDayBuyHostTempList.append(hostCoreMemBiBigSmallList[posCpuMin])
            # 将原列表中已经添加的相关add请求,去除已经添加过的部分
            dayListOne.addRequireList_Single = dayListOne.addRequireList_Single[(posTempList[posCpuMin] + 1):]
            flag = 0
        # 找到memSize差值最小的服务器,此时只考虑memSize
        elif dayListOne.averageSingleCoreMemBi < 1 and flag == 1:
            posMemMin = memSizeDValueTempList.index(min(memSizeDValueTempList))
            oneDayOutput.oneDayBuyHostTempList.append(hostCoreMemBiBigSmallList[posMemMin])
            # 将原列表中已经添加的相关add请求,去除已经添加过的部分
            dayListOne.addRequireList_Single = dayListOne.addRequireList_Single[(posTempList[posMemMin] + 1):]
            flag = 0



# 购买、分配算法
def shoppingAndDistribution(hostCoreMemBiBigList, hostCoreMemBiSmallList, dayListAll):
    # 若平均核内比 > 1,
    # 分别遍历dayList.addRequireList_Double与dayList.addRequireList_Single列表中的
    # 每个虚拟机请求对应的的vmCpuNum(核数),并进行累加与服务器的cpuNum比较
    # 否则遍历MemSize

    # 尝试凑数、分配
    buyHostList_Double = [0 for i in range(len(dayListAll))]
    buyHostList_Single = [0 for i in range(len(dayListAll))]
    costAll = 0
    costHardWareAll = 0
    # 遍历dayListAll
    for i in range(len(dayListAll)):
        # 创建Output类
        oneDayOutput = OutPut()

        # 判断双节点平均核内比
        # 大于1,表明cpuNum大,在hostCoreMemBiBigList中寻找购买的服务器
        # 小于1,表明memSize大,在hostCoreMemBiSmallList中寻找购买的服务器
        if dayListAll[i].averageDoubleCoreMemBi >= 1:
            doubleShopping(oneDayOutput, dayListAll[i], hostCoreMemBiBigList)
        else:
            doubleShopping(oneDayOutput, dayListAll[i], hostCoreMemBiSmallList)

        buyHostList_Double[i] = oneDayOutput.oneDayBuyHostTempList

        # 打印出来的是每一天双节点虚拟机请求所需要购买的服务器(上下同时打开注释)
        print('________第%d天________' % (i+1))
        print('________双________')
        print(len(oneDayOutput.oneDayBuyHostTempList))
        for buyHost in oneDayOutput.oneDayBuyHostTempList:
            print(buyHost.hostType, buyHost.hostHardWareCost)
            costAll += (buyHost.hostHardWareCost + buyHost.hostDayCost*(len(dayListAll)-i))
            costHardWareAll += buyHost.hostHardWareCost

        if dayListAll[i].averageSingleCoreMemBi >= 1:
            singleShopping(oneDayOutput, dayListAll[i], hostCoreMemBiBigList)
        else:
            singleShopping(oneDayOutput, dayListAll[i], hostCoreMemBiSmallList)

        buyHostList_Single[i] = oneDayOutput.oneDayBuyHostTempList

        # 打印出来的是每一天单节点虚拟机请求所需要购买的服务器
        print('________单________')
        print(len(oneDayOutput.oneDayBuyHostTempList))
        for buyHost in oneDayOutput.oneDayBuyHostTempList:
            print(buyHost.hostType, buyHost.hostHardWareCost)
            costAll += (buyHost.hostHardWareCost + buyHost.hostDayCost*(len(dayListAll)-i))
            costHardWareAll += buyHost.hostHardWareCost
    # 打印出来的是总花销和总硬件花销
    print(costAll, costHardWareAll)


# 将输入的数据处理,输出为hostListAll, vmListAll, dayListAll列表
# hostListAll, vmListAll 分别代表服务器总表与虚拟机总表
# dayListAll中存储800天的数据,每一个列表元素为一个类(oneDay)
def inputData(allData):
    flag = 0
    for i in range(len(allData)):
        if allData[i].isdigit():
            flag += 1
            # flag=1 准备处理出服务器总表
            if flag == 1:
                hostTypeNum = int(allData[i])
                hostListAll = [allData[i + j + 1] for j in range(hostTypeNum)]
            # flag=2 准备处理出虚拟机总表
            elif flag == 2:
                vmTypeNum = int(allData[i])
                vmListAll = [allData[i + j + 1] for j in range(vmTypeNum)]
            # flag=3 接收所有天的全部请求 本页代码中的小弯弯
            elif flag == 3:
                dayNum = int(allData[i])
                flag1 = 0
                dayListAll = [0 for j in range(dayNum)] #存DayRequire类
                # 遍历800日后的全部输入 可体会一下同级下的break
                for j in range(i + 1, len(allData)):
                    if allData[j].isdigit():
                        flag1 += 1
                        # 读不懂可解开下句封印 尝试观察输出
                        # print(allData[j], allData[j+1])
                        #过滤请求类数据,接收每日请求的数值 譬如第一日142
                        if flag1 <= dayNum:
                            #新建一个类 用于接收每一天的请求数据
                            oneDay = DayRequire()
                            oneDay.requireNum = int(allData[j])
                            # 读不懂可解开下句封印 尝试观察输出
                            # print(oneDay.requireNum)
                            # 下方for循环接收每一天的请求数据 存到oneDay的类中 传给dayListAll
                            for k in range(j + 1, j + oneDay.requireNum + 1):
                                # 按逗号切分每条请求
                                tmpeList = allData[k].split(',')
                                # 切分后的数组若只有两项表明为del请求 传给oneDay.delRequireList
                                if len(tmpeList) == 2:
                                    # 清除多余空格、括号
                                    oneDay.requireType = tmpeList[0].replace('(', '')
                                    oneDay.vmId = tmpeList[1].replace(')', '').replace(' ', '')
                                    oneDay.delRequireListAppend()
                                # 切分后的数组若有三项表明为add请求 传给oneDay.addRequireList
                                elif len(tmpeList) == 3:
                                    # 清除多余空格、括号
                                    oneDay.requireType = tmpeList[0].replace('(', '')
                                    oneDay.vmType = tmpeList[1].replace(' ', '')
                                    oneDay.vmId = tmpeList[2].replace(')', '').replace(' ', '')
                                    oneDay.addRequireListAppend()
                            dayListAll[flag1 - 1] = oneDay
                # 执行完flag==3中的内容后,可直接跳出最外层for循环
                break
    # 为Host类赋值,使hostListAll中每一个元素为一个Host类
    i = 0
    for host in hostListAll:
        #分割数据去除空格、括号
        host = host.split(',')
        host[0] = host[0].replace('(', '').replace(' ', '')
        host[4] = host[4].replace(')', '').replace(' ', '')

        #赋值数据
        tmpeHost = Host()
        tmpeHost.hostType = host[0]
        tmpeHost.hostCpuNum = int(host[1])
        tmpeHost.hostMemSize = int(host[2])
        tmpeHost.hostHardWareCost = int(host[3])
        tmpeHost.hostDayCost = int(host[4])
        tmpeHost.xingJiaBi()
        tmpeHost.coreMemBi()
        hostListAll[i] = tmpeHost
        i += 1
    # 为Vm类赋值,使vmListAll中每一个元素为一个Vm类
    i = 0
    for vm in vmListAll:
        # 分割数据去除空格、括号
        vm = vm.split(',')
        vm[0] = vm[0].replace('(', '').replace(' ', '')
        vm[3] = vm[3].replace(')', '').replace(' ', '')

        # 赋值数据
        tmpeVm = Vm()
        tmpeVm.vmType = vm[0]
        tmpeVm.vmCpuNum = int(vm[1])
        tmpeVm.vmMemSize = int(vm[2])
        tmpeVm.vmDoubleOrNot = int(vm[3])
        tmpeVm.coreMemBi()
        vmListAll[i] = tmpeVm
        i += 1
    i = 0

    return hostListAll, vmListAll, dayListAll

def main():
    # to read standard input
    # process
    # to write standard output
    # sys.stdout.flush()

    #以training-1.txt为示例
    filename = "training-1.txt"

    #按换行分割全部数据
    allData = readTxt(filename).split('\n')
    # 根据下一条注释可以返回分割后的数据
    # print(allData[0])
    [hostListAll, vmListAll, dayListAll] = inputData(allData)
    # 数据预处理
    [hostCoreMemBiBigList, hostCoreMemBiSmallList] = dataPraparation(hostListAll, vmListAll, dayListAll)
    # 购买分配算法
    shoppingAndDistribution(hostCoreMemBiBigList, hostCoreMemBiSmallList, dayListAll)

    # 根据下一条的输出,可显示第一天第一条请求
    # print(dayListAll[0].addRequireList[0])



if __name__ == "__main__":
    main()


总结

Ps:

  • 在这里,非常感谢resetmefun朋友对鄙人代码问题的纠正!
  • 如果大家有什么好的思路,或者本文代码的不妥之处,欢迎在评论区吐槽留言~

猜你喜欢

转载自blog.csdn.net/weixin_44459972/article/details/115017212