【算法设计与分析】实验——二维0-1背包问题(算法分析题:算法思路),独立任务最优调度问题(算法实现题:实验过程,描述,小结)

发布于:2025-06-03 ⋅ 阅读:(29) ⋅ 点赞:(0)

说明:博主是大学生,有一门课是算法设计与分析,这是博主记录课程实验报告的内容,题目是老师给的,其他内容和代码均为原创,可以参考学习,转载和搬运需评论吱声并注明出处哦。

要求:3-1为算法分析题,写出主要的算法即可。3-2为算法实现题,要求写出:实验名称、实验过程描述(包括程序代码、测试用例、实验结果分析)、实验小结(包括实验过程中遇到的问题及体会)。

算法分析题3-1 二维0-1背包问题

给定n种物品和一背包。物品i的重量是wi ,体积是bi,其价值为vi,背包的容量为c,容积为d。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?在选择装入背包的物品时,对每种物品i只能有两种选择,即装入背包和不装入背包。不能将物品i装入背包多次,也不能只装入部分的物品i。尝试设计一个解决此问题的动态规划算法,并分析算法的时间复杂性。

主要算法思路:

设计一个三位数组dp,存放的值dp[i][j][k]代表前i个物品已经安排好,背包重量为j,体积为k时已经放入的物品的总价值。初始值dp[0][j][k]为0;对于每个物品,有两种选择,选和不选,首先判断是否能放下背包中,如果能,判断放入后,减去重量和体积,加上价值,是否比当前价值大,如果大的话加入,小的话不加入。

时间复杂性分析:

算法实现利用了三层循环,时间复杂性为O(n*c*d).

# a存放所有物品信息(二维列表a[价值][重量][体积]),c背包容量,d容积,dp动态规划数组
def value_max(a, c, d):
    n = len(a)
    dp = [[[0 for _ in range(d + 1)] for _ in range(c + 1)] for _ in range(n + 1)]
    for i in range(1, n+1):  # 遍历每个物品
        for j in range(c + 1):  # 遍历所有可能的重量
            for k in range(d + 1):  # 遍历所有可能的体积
                if j >= a[i-1][1] and k >= a[i-1][2]:
                    dp[i][j][k] = max(
                        dp[i - 1][j][k],  # 不装入
                        dp[i - 1][j - a[i-1][1]][k - a[i-1][2]] + a[i-1][0]  # 装入
                    )
                else:
                    dp[i][j][k] = dp[i - 1][j][k]

    return dp[n][c][d]  # 最大价值

算法实现题3-2 独立任务最优调度问题

问题描述:

用2台处理机A和B处理n个作业。设第i个作业交给机器A处理时需要时间ai,若由机器B来处理,则需要时间bi。由于各作业的特点和机器的性能关系,很可能对于某些i,有ai>=bi,而对于某些j, j≠i,有aj<bj。既不能将一个作业分开由2台机器处理,也没有一台机器能同时处理2个作业。
设计一个动态规划算法,使得这2台机器处理完这n个作业的时间最短(从任何一台机器开工到最后一台机器停工的总时间)。
研究一个实例: (a1,a2,a3,a4,a5,a6)=(2,5,7,10,5,2);(b1,b2,b3,b4,b5,b6)=(3,8,4,11,3,4)。 对于给定的2台处理机A 和B处理n 个作业,找出一个最优调度方案,使2台机器处理完这n个作业的时间最短。

编程任务:

对于给定的2台处理机A B处理n 个作业,找出一个最优调度方案,使2台机器处理

完这n 个作业的时间最短。

数据输入:

由文件input.txt提供输入数据。文件的第1行是1个正整数n, 表示要处理n个作业。接下来的2行中,每行有n 个正整数,分别表示处理机A 和B 处理第i 个作业需要的处理时间。

结果输出:

程序运行结束时,将计算出的最短处理时间输出到文件output.txt 中。

实验名称

独立任务最优调度问题

实验过程描述

程序代码

# 共有n个作业,a,b是机器处理作业需要时间的列表
# dp[i][j]表示处理前i个作业,机器A花费时间为j时,机器B的最小处理时间
def schedule(n, a, b):
    sum_a = sum(a)
    dp = [[float('inf')] * (sum_a + 1) for _ in range(n + 1)]
    dp[0][0] = 0
    for i in range(1, n + 1):
        for j in range(sum_a + 1):
            if j >= a[i - 1] and dp[i - 1][j - a[i - 1]] != float('inf'):
                dp[i][j] = dp[i - 1][j - a[i - 1]]  # A处理i
            if dp[i - 1][j] != float('inf'):
                dp[i][j] = min(dp[i][j], dp[i - 1][j] + b[i - 1])  # B处理i
    min_time = float('inf')
    # 所有可能的j中,max(j, dp[n][j])的最小值
    for j in range(sum_a + 1):
        if dp[n][j] != float('inf'):
            min_time = min(min_time, max(j, dp[n][j]))
    return min_time

# 主程序
with open('input.txt', 'r') as f:
    n = int(f.readline())
    a = list(map(int, f.readline().split()))
    b = list(map(int, f.readline().split()))
result = schedule(n, a, b)
with open('output.txt', 'w') as f:
    f.write(str(result))
print("最短处理时间:", result)

测试用例

实验结果分析

本次实验实现了独立任务最优调度问题,两次测试用例分别对应的结果为49和192。

主要算法思路:

用动态规划设置一个dp数组,表示处理前i个作业,机器A花费时间为j时,机器B的最小处理时间(A,B也可以换顺序),然后下标从小到大遍历dp数组,对于每一个作业,有两种选择,a处理或者b处理,比较两者时间大小,选取花费时间较小的即可。而最终的结果,是对于所有a可能的处理时间中,也就是所有可能的j中,max(j, dp[n][j])的最小值。

时间复杂度分析:

双层循环,外层循环n次,内层循环sum_a+1次,所以时间复杂度为O(n*sum_a)

实验小结

问题

这道题在算法思路方面并没有特别大的问题,主要问题在于编写代码的过程中,如何去初始化dp数组,也就是语句

dp = [[float('inf')] * (sum_a + 1) for _ in range(n + 1)]
dp[0][0] = 0

首先考虑到dp数组一维大小要定义为机器A处理时间的最大值,也就是最坏情况当所有作业都由A来处理时;而数组的二维大小就是作业的总个数,这里的细节是遍历时要从1开始遍历,不然会出现数组下标错误。

体会

实践实现了动态规划算法的应用,主要语法学习点为使用float('inf')表示无穷大


网站公告

今日签到

点亮在社区的每一天
去签到