[算法]是否能通过考试

是否能通过考试

题目描述

Description

小张想要通过明天的考试。他知道考题的分值分布,也知道考试中要拿到每一个题目需要耗费的时间。假设考试时长为h,共n个题目,需要拿到p分才能通过考试。现在已知每个考题的得分与耗时,请你判断小张能否通过合理安排时间,而通过考试,并给出通过考试的最短时间。

Input

输入第一行为测试用例个数.每一个用例有若干行,第一行为任务数量n、考试时常h、通过分数p,下面的n行是每一个题目的耗时和得分。所有数值用空格分开。

Output

对每一个用例输出一行,如果能够通过考试,则输出“YES”和消耗最短时间,用空格隔开。 否则,输出“NO”。

Sample Input 1

1
5 40 21 
12 10 
16 10 
20 10 
24 10 
8 3 

Sample Output 1

YES 36

题目解析

实际上就是一个背包问题,

思路解析

分数=价值, 时间 =重量,套背包问题的模板就好

dp数组结构

i = 问题的个数, j = 当前考试时间, dp[i] [j]表示在不超过考试时间j的情况下,做到第i个问题时最多能拿多少分.

其中状态转移方程等同于背包问题

如何满足需要拿到p分才能通过考试?

若数组中最后一行一列的数大于p,证明可以拿到p分,此时

  1. 回溯找,即更新完dp数组后再找大于p分的最小时间.
  2. 在遍历过程中记录,若大于p分时,更新当前的时间值(也就是j),
代码实现(python)
if __name__ == '__main__':

    for _ in range(int(input())):
        n, h, p = list(map(int, input().strip().split()))  # 最大耗时就是最大容量
        h_arr = []  # 耗时  耗时作为重量
        p_arr = []  # 分数  分数作为价值
        for i in range(n):
            temp = list(map(int, input().strip().split()))
            h_arr.append(temp[0])
            p_arr.append(temp[-1])

        dp = [[0] * (h + 1) for _ in range((n + 1))]
        min_tar = h + 1
        for i in range(1, n + 1):
            for j in range(1, h + 1):
                if h_arr[i - 1] <= j:  # 如果可以放
                    op_add = dp[i - 1][j - h_arr[i - 1]] + p_arr[i - 1]  # 放入当前物品\
                    op_not = dp[i - 1][j]
                    dp[i][j] = max(op_add, op_not)
                else:  # 不能放
                    dp[i][j] = dp[i - 1][j]
                if dp[i][j] >= 21:  # 如果满足了条件,则记录当前时间
                    min_tar = min(min_tar, j)
        if dp[-1][-1] < p:
            print("NO")
        else:
            print("YES " + str(min_tar))

发布了71 篇原创文章 · 获赞 21 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_33935895/article/details/103213133