蓝桥杯作物杂交(递归)

1. 问题描述:

作物杂交是作物栽培中重要的一步。已知有 N种作物 (编号 1 至 N ),第 i 种作物从播种到成熟的时间为 Ti。作物之间两两可以进行杂交,杂交时间取两种中时间较长的一方。如作物 A 种植时间为 5 天,作物 B 种植时间为 7 天,则 AB 杂交花费的时间为 7 天。作物杂交会产生固定的作物,新产生的作物仍然属于 N 种作物中的一种。
初始时,拥有其中 M种作物的种子 (数量无限,可以支持多次杂交)。同时可以进行多个杂交过程。求问对于给定的目标种子,最少需要多少天能够得到。
如存在 4 种作物 ABCD,各自的成熟时间为 5 天、7 天、3 天、8 天。初始拥有 AB 两种作物的种子,目标种子为 D,已知杂交情况为 A × B → C,A × C → D。则最短的杂交过程为:
第 1 天到第 7 天 (作物 B 的时间),A × B → C。
第 8 天到第 12 天 (作物 A 的时间),A × C → D。
花费 12 天得到作物 D 的种子。
输入描述
输入的第 1 行包含 4 个整数 N, M, K, T,N表示作物种类总数 (编号 1 至 N),M表示初始拥有的作物种子类型数量,K表示可以杂交的方案数,T表示目标种子的编号。
第 2 行包含 N 个整数,其中第 i个整数表示第 i 种作物的种植时间 Ti(1<=Ti<=100) 
第 3 行包含 M 个整数,分别表示已拥有的种子类型 Kj (1 <= Kj ≤ M),Kj 两两不同。
第 4 至 K+ 3 行,每行包含 3 个整数 A, B,C,表示第 A类作物和第 B 类作物杂交可以获得第 C 类作物的种子。
其中,1 <= N<= 2000, 2<= M <= N, 1 <= K <=10^5, 1 <= T <= N
保证目标种子一定可以通过杂交得到。
输出描述
输出一个整数,表示得到目标种子的最短杂交时间。
输入输出样例
示例
输入
6 2 4 6
5 3 4 6 4 9
1 2
1 2 3
1 3 4
2 3 5
4 5 6
输出
16
样例说明
第 1 天至第 5 天,将编号 1 与编号 2 的作物杂交,得到编号 3 的作物种子。
第 6 天至第 10 天,将编号 1 与编号 3 的作物杂交,得到编号 4 的作物种子。
第 6 天至第 9 天,将编号 2 与编号 3 的作物杂交,得到编号 5 的作物种子。
第 11 天至第 16 天,将编号 4 与编号 5 的作物杂交,得到编号 6 的作物种子。
总共花费 16 天。
运行限制
最大运行时间:1s
最大运行内存: 256M

来源:https://www.lanqiao.cn/problems/506/learning/

2. 思路分析:

① 分析题目可以知道最容易想到的是从目前已有的种子进行杂交,通过搜索所有可能的杂交方案得到目标种子,递归的时候记录花费情况,但是由题目的数据规模K最大为10^5可以知道直接搜索全部可能的杂交方案肯定会超时,正向递归比较耗时,那么不妨这样想,反过来行不行呢?我们可以反向递归一直到当前递归的目标种子为目前已有的种子,所以一开始的时候可以从目标编号的种子T出发,往前进行推导,因为我们知道要想得到目标种子那么肯定是有一步是通过杂交得到的,通过循环遍历找到当前可以得到目标种子编号T的杂交方案,然后再使用相同的方法递归这个杂交方案A * B = C中的种子编号A、B(往前找哪个杂交方案可以得到种子A与种子B),也就是下一次递归的目标种子编号分别为A和B,直到当前递归的目标种子编号为已有的种子的时候那么说明在使用种子T往前推的时候可以通过现有的种子通过一系列的杂交得到目标种子T。我们可以写一个有返回值的递归方法,当我们递归的时候发现目前已经有的种子中包含了当前的递归种子的时候说明可以通过当前的种子通过一系列的杂交得到目标编号的种子T,这个时候返回0即可,并且在往下递归的时候需要先加上当前A与B杂交得到C的最大种植时间,表示当前的为获得目标种子C所需要的时间,整个思路还是挺好理解的,画一下从目标编号一直往前推导的过程会更好理解一点,核心的代码主要就是递归的代码:

② 递归的时候每一次都是找到当前需要的目标编号的种子,所以我们就需要在所有可能的杂交方案中找到这个目标编号

返回0是因为当前目标种子在目前已有的种子中已经存在了,而在往下递归的时候我们是加上了当前得到种子C的A,B的最大种植时间的,所以最后需要返回0,其实也不难理解,考虑目前只有一种方案可以得到目标编号的种子,那么最终返回0的结果才是正确的(从简单一点的例子考虑会更容易理解一点),因为我再递归之前已经加上了得到目标种子C的最大时间了

③ 因为使用的是python语言,所以在一开始的时候A * B = C的杂交方案可以通过元组的形式封装在一起加入到列表中,这样在递归的时候可以直接遍历这个列表找到可能的杂交方案

3. 代码如下:

from typing import List


class Solution:
    def solve(self, N: int, M: int, K: int, T: int, plantTime: List[int], seeds: List[int], program):
        def dfs(target):
            res = 0
            if target in seeds: return 0
            for i in range(K):
                if program[i][2] == target:
                    # 注意输入数据与下标的转换, 后面需要减1
                    res += max(dfs(program[i][0]), dfs(program[i][1])) + max(plantTime[program[i][0] - 1],
                                                                             plantTime[program[i][1] - 1])
                    break
            return res
        res = 10 ** 9
        # 有可能存在多个杂交的方案获取目标种子编号T这个时候需要搜索所有能够获得种子T的杂交方案
        # 从中找到一个花费最小的
        for i in range(K):
            if program[i][2] == T:
                res = min(res, max(dfs(program[i][0]), dfs(program[i][1])) + max(plantTime[program[i][0] - 1], plantTime[program[i][1] - 1]))
        return res


if __name__ == '__main__':
    N, M, K, T = map(int, input().split())
    plantTime = list(map(int, input().split()))
    seeds = list(map(int, input().split()))
    program = list()
    # program存储的是作物的杂交方案
    for i in range(K):
        A, B, C = map(int, input().split())
        # 列表中的元素为元组类型这样封装会更方便一点
        program.append((A, B, C))
    print(Solution().solve(N, M, K, T, plantTime, seeds, program))

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值