作物杂交蓝桥杯

题目大意
作物杂交是作物栽培中重要的一步。已知有 NN​​​​​ 种作物 (编号 11​​​​​ 至 NN​​​​​ ),第 ii​​​​​ 种作物从播种到成熟的时间为 t_it
i

​​​​​。作物之间两两可以进行杂交,杂交时间取两种中时间较长的一方。如作物 A 种植时间为 55​​ 天,作物 B 种植时间为 77​ 天,则 ABAB​​​ 杂交花费的时间为 77​​​​ 天。作物杂交会产生固定的作物,新产生的作物仍然属于 NN​​​​​ 种作物中的一种。

初始时,拥有其中 MM 种作物的种子 (数量无限,可以支持多次杂交)。同时可以进行多个杂交过程。求问对于给定的目标种子,最少需要多少天能够得到。

如存在 44​​​​​​ 种作物 ABCDABCD​​​​​​,各自的成熟时间为 55​​​​​​ 天、77​​​​​ 天、33​​​​ 天、88​​​ 天。初始拥有 ABAB​​ 两种作物的种子,目标种子为 DD​,已知杂交情况为 A \times B \rightarrow CA×B→C,A \times C \rightarrow DA×C→D。则最短的杂交过程为:

第 11 天到第 7 天 (作物 B 的时间),A \times B \rightarrow CA×B→C。

第 88​ 天到第 1212 天 (作物 A 的时间),A \times C \rightarrow DA×C→D​。

解题思路
若作物 AA、BB 可杂交出作物 ii,则我们称 AA、BB 为 ii 的父亲 ,ii 为 AA、BB 的儿子。显然一种种子可以拥有多个父亲,也可以拥有多个儿子。

我们定义 dp[i]dp[i]​​ 表示得到第 ii​ 个作物所需的最少天数。根据题意可得:若作物 AA​、BB​ 可杂交出作物 ii​,那么 ​

dp[i] = \min(dp[i] , \max(dp[A],dp[B]) + max(t[A] , t[B]))
dp[i]=min(dp[i],max(dp[A],dp[B])+max(t[A],t[B]))
于是我们可以将已经拥有的种子放入队列,然后每次取出的时候,更新它所有儿子的答案(更新前要先判断一下该儿子的另一个父亲是否已经得到了)。

由于每个种子只会入队出队一次,所以每个种子都只会遍历一遍和它有关的杂交方案,那么复杂度就等于总杂交方案数。

这样乍一看好像可以,但有个致命的问题:我们只会用作物 AA 更新一次作物 ii​ 的答案。

举个例子:

设作物 55 和作物 44 是作物 11 的父亲、dp[5]=10,dp[4] = 0 , t[5] = 10 , t[4]= 0dp[5]=10,dp[4]=0,t[5]=10,t[4]=0。

那么当作物 55​ 出队时,作物 55​ 将会更新作物 11​ 的答案,即 dp[1] = \min(dp[1], \max(dp[5],dp[4] + \max(t[5],t[4])))dp[1]=min(dp[1],max(dp[5],dp[4]+max(t[5],t[4])))​​。

而后,作物 55​ 的某个父亲出队时,它将会更新作物 55​ 的答案,即 dp[5]dp[5]​。若更新后 dp[5]dp[5]​ 的值小于 1010​,则我们也应该再用 dp[5]dp[5]​ 去更新一次 dp[1]dp[1]​。不过由于作物 55​ 已经出队了,它将不会再去更新它的儿子。这样就会导致答案错误。

为了避免这种情况,我们可以使用优先队列,按照 dp[i]dp[i]​ 的值从小到大出队。若一个作物的 dpdp 值减少了,则需要重新入队。

或者维护一个时间戳数组 vec[],将第 ii​​ 种作物存入 vec[dp[i]] 中。然后从前往后枚举时间。对于某个时刻,将该时刻 vec 数组中的作物放入队列以更新它们的儿子。若一个作物的 dpdp 值减少了,也需要加入新的时间戳数组中。

最后的答案为 dp[dp[​目标种子]]​​(注意作物 AA 和作物BB​​ 可能可以杂交出多种其它作物,不过同一杂交方案不会多次输出)。

AC_Code
import java.io.*;
import java.util.*;
class InputReader{
    private final static int BUF_SZ = 65536;
    BufferedReader in;
    StringTokenizer tokenizer;
    public InputReader(InputStream in) {
        super();
        this.in = new BufferedReader(new InputStreamReader(in),BUF_SZ);
        tokenizer = new StringTokenizer("");
    }
    private String next() {
        while (!tokenizer.hasMoreTokens()) {
            try {
                tokenizer = new StringTokenizer(in.readLine());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken();
    }
    public int nextInt() {
        return Integer.parseInt(next());
    }
}
public class Main {
    private final static int N = 2010;
    private static boolean[] ok = new boolean[N];
    private static boolean[] vis = new boolean[N];
    private static int n , m , K , T , x , y , z;
    private static int[] t = new int[N];
    private static int[] dp = new int[N];
    private static ArrayList<Integer>[] vec = Arrays.initializeWithDefaultArrayListOfIntInstances(N * N);
    private static ArrayList<Pair<Integer, Integer>>[] G = Arrays.initializeWithDefaultArrayListOfPairOfIntInstances(N);
    private static LinkedList<Integer> que = new LinkedList<Integer>();

    private static void bfs() {
        int up = 0;
        for (int i = 0; i <= up; i++) {
            for (int j : vec[i]) {
                if (vis[j]) {
                    continue;
                }
                vis[j] = true;
                que.offer(j);
                while (!que.isEmpty()) {
                    int u = que.peek();
                    que.poll();
                    for (Pair<Integer, Integer> k : G[u]) {
                        int y = k.first;
                        int z = k.second;
                        if (!ok[y]) {
                            continue;
                        }
                        int now = Math.max(dp[u], dp[y]) + Math.max(t[u], t[y]);
                        if (now < dp[z]) {
                            dp[z] = now;
                            vec[dp[z]].add(z);
                        }
                        ok[z] = true;
                        up = Math.max(up, now);
                    }
                }
            }
        }
    }
    public static void main(String[] args) {
        InputReader cin = new InputReader(System.in);
        n = cin.nextInt();
        m = cin.nextInt();
        K = cin.nextInt();
        T = cin.nextInt();
        java.util.Arrays.fill(dp , 1000000000);
        for (int i = 1; i <= n; i++) {
            t[i] = cin.nextInt();
        }
        for (int i = 1; i <= m; i++) {
            x = cin.nextInt();
            ok[x] = true;
            dp[x] = 0;
            vec[0].add(x);
        }
        for (int i = 1; i <= K; i++) {
            x = cin.nextInt();
            y = cin.nextInt();
            z = cin.nextInt();
            G[x].add(new Pair<Integer, Integer>(y, z));
            G[y].add(new Pair<Integer, Integer>(x, z));
        }
        bfs();
        System.out.println(dp[T]);
    }
}


final class Pair<T1, T2> {
    public T1 first;
    public T2 second;
    public Pair() {
        first = null;
        second = null;
    }
    public Pair(T1 firstValue, T2 secondValue) {
        first = firstValue;
        second = secondValue;
    }
    public Pair(Pair<T1, T2> pairToCopy) {
        first = pairToCopy.first;
        second = pairToCopy.second;
    }
}
final class Arrays {
    public static ArrayList<Integer>[] initializeWithDefaultArrayListOfIntInstances(int length) {
        ArrayList<Integer>[] array = new ArrayList[length];
        for (int i = 0; i < length; i++) {
            array[i] = new ArrayList<Integer>();
        }
        return array;
    }
    public static java.util.ArrayList<Pair<Integer, Integer>>[] initializeWithDefaultArrayListOfPairOfIntInstances(int length) {
        ArrayList[] array = new ArrayList[length];
        for (int i = 0; i < length; i++) {
            array[i] = new ArrayList<>();
        }
        return array;
    }
}

copy
视频讲解配套源码
package lanqiao;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class lanqiao202009
{
    static int INF=Integer.MAX_VALUE;
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        int N=0,M=0,K=0,T=0;//N种作物,M个初始种子,K种杂交方案,要得到T种子
        N=sc.nextInt();
        M=sc.nextInt();
        K=sc.nextInt();
        T=sc.nextInt();
        int[] dp=new int[N+1];//得到作物i所需要的最短时间
        int[] ctime=new int[N+1];//每个种子的作物种植的时间
        Arrays.fill(dp, INF);//开始时间都无穷大
        for(int i=1;i<=N;i++)ctime[i]=sc.nextInt();//录入每个种子生长需要的时间
        for(int i=1;i<=M;i++)dp[sc.nextInt()]=0;//M个已知作物,不需要杂交得到
        
        ArrayList<bean>[] ways=new ArrayList[N+1];//每个作物都可以有多个杂交途径得到。way[i]存放 i种子所有可以杂交的方案
        for(int i=1;i<=N;i++)ways[i]=new ArrayList<bean>();//对象数组要一个一个实例化里面的元素
        for(int i=1;i<=K;i++)
        {
            int fa=sc.nextInt();
            int fb=sc.nextInt();
            int gc=sc.nextInt();
            //一种方案能得到c的记录下来
            ways[gc].add(new bean(fa,fb,Math.max(ctime[fa], ctime[fb])));//时间以2个爸爸中长的为准
        }
        System.out.println(DFS(dp,ways,T));
    }

    private static int DFS(int[] dp,ArrayList<bean>[] ways,int T)
    {
        if(dp[T]!=INF)return dp[T];//已经dfs到了作物T的最优杂交时间,直接使用,记忆化搜索
        for(int i=0;i<ways[T].size();i++)//穷举作物T的所有已知的杂交方案
        {
            int famin=DFS(dp,ways,ways[T].get(i).fa);//要知道孩子,必须先知道他2个爸爸的时间
            int fbmin=DFS(dp,ways,ways[T].get(i).fb);
            //dp状态转移方程:T的最优时间,等于若干种已知方案dp[T],和当前方案 花费的时间和杂交得到fa 和 fb的时间和
            dp[T]=Math.min(dp[T], Math.max(famin, fbmin)+ways[T].get(i).time);
        }
        return dp[T];
    }
}

class bean
{
    int fa;
    int fb;
    int time;//a 和 b 需要time杂交得到 c
    public bean(int a,int b,int t)
    {
        fa=a;fb=b;time=t;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值