pan.baidu.com/s/1w-VSMWmr9ntEWWdxZoD4Yw
码:jnlh
算法分析与设计 | |||||
时间 | 2020.5.17 | ||||
实验名称 | 非单位时间任务安排问题 | ||||
实验目的 | 通过上机实验,要求深度掌握贪心算法的问题描述、算法设计思想、程序设计。 | ||||
实验原理 | 利用贪心思想,根据题目所给出的条件,求解问题,计算出最小总误时惩罚。 | ||||
实验步骤 | 问题分析: 具有截止时间和误时惩罚的任务安排问题可描述如下 实验任务:对于给定的n个任务,编程计算总误时惩罚最小的最优时间表。 首先将任务按其截止时间非减序排序; 对任务1,2 ,……,i,如果截止时间为d,则设最小误时惩罚为 p( i , d ) 。 递归式为:p( i , d ) = min{ p(i-1, d)+wi ,p(i-1, min{d, di}-ti) } p(i-1, d)+wi 表示决定不做第 i 个任务,p(i-1, min{d, di}-ti) 表示决定要做第 i 个任务,这时必须在第 i 个任务的截至时间前做完它(即 min{d, di}-ti) 算法思想:先将任务集按照结束时间非递减排序; 设置数组p[ ][ ]来保存 p( i , d )的结果(本算法的局限性:时间只能为整数值)。 对于第一个任务来说,如果时间少于它需要执行的时间 t,则会遭受惩罚——p[1][ 0 ~ tasks[1].t ]=tasks[i].w; 时间够则不然——p[1][ 0 - tasks[1].t ]=0。 对于第 i 个任务 的任务来说(i取2到n),就如果时间少于它需要执行的时间 t,则不能执行它了,只能放弃—— p[ i ][ 0 ~ tasks[1].t ]=p(i-1, d)+wi; 如果时间够,则看是执行了好还是不执行好—— p[ i ][ tasks[1].t ~d ] = min{ p(i-1, d)+wi ,p(i-1, min{d, di}-ti) }。 即类似于动态规划算法,每次都选择最佳选项,使得局部最优最终得到全局最优; 算法步骤:① 将用例数据从文件中读取并初始化需要的数据; ② 将所有工作按照截止时间从小到大排序; ③遍历排序后的任务,对每一项任务做如下处理: ④遍历所取的截至时间x(从0到所有任务的最大的截取时间), 如果该截取时间x大于当前任务i的截止时间,则必然超时,令p[i][j]=p[i-1][j]+task[i].w(当前任务超时惩罚)即可; 如果x小于当前任务i的截止时间,那么从超时与不超时两种情况里面选出最小的min{p[i-1][j]+task[i].w、p[i-1][x-task[i].t]}作为p[i][d]即可; ⑤当所有任务遍历结束,p[n-1][d]即为最小超时惩罚; | ||||
关键代码 | 关键代码(带注释)1. 核心部分dyna()for循环对排序后的每个任务进行贪心选择求最小的超市惩罚; 首先令p[i][j]=p[i-1][j]+task[i].w(当前任务超时惩罚), 如果x小于当前任务i的截止时间,那么从超时与不超时两种情况里面选出最小的min{p[i-1][j]+task[i].w、p[i-1][x-task[i].t]}作为p[i][d]即可; 2. init初始化函数(从文件中读) 读出每一个任务的时间、截止时间、超时惩罚,并按截止时间来从小到大排列,并对表示i任务d截止时间超时惩罚的f[i][d]进行初始化; 3. 计算时间部分代码通过时间函数QueryPerformanceFrequency与cpu的主频频率得到程序段的运行时间,可以精确到微妙,比clock函数更精确一些; 4. 数据生成代码与上述两个实验的数据生成方法相同,使用随机数函数来生成; | ||||
测试结果 | 运行结果截图及分析对于题目样例: 运行正确; 对于三种不同规模的数据文件(10、100、1000) 时间增长较为明显,大致接近O(n^2); 时间复杂度分析: 分为两部分,初始化部分的快排算法需要O(nlogn)的时间复杂度,贪心选择部分的双重for循环则需要O(nd),总共需要 O(nlogn + nd)d=max{di}; 空间复杂度分析: 最少需要O(n*d)d=max{di},主要存储动规表; | ||||
实验心得 | 通过这道问题,我进一步的理解了贪心选择算法与动态规划算法之间的联系——最优子结构,通过局部最优一步一步的推导出最终的整体最优;也进一步的掌握了贪心算法的使用方法,尤其是贪心选择的选择方法,也使我的编程能力有了进一步的提升; |