【单源最短路/DFS/spfa/dijkstra】2020年蓝桥杯真题之作物杂交

⭐️前面的话⭐️

本篇文章介绍来自2020年蓝桥杯真题之作物杂交,考察算法DFS,BFS,SPFA,dijkstra,展示语言java(c++代码后续更新)。

博客主页:未见花闻的博客主页
欢迎关注点赞收藏⭐️留言
本文由未见花闻原创,CSDN首发!
首发时间:2023年4月6日
✉️坚持和努力一定能换来诗与远方!
推荐书籍:《算法》,《算法导论》
参考在线编程网站:牛客网力扣
博主的码云gitee,平常博主写的程序代码都在里面。
博主的github,平常博主写的程序代码都在里面。
作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!


导航小助手

  • ⭐️作物杂交⭐️
    • 题目详情
    • 解题思路
    • 源代码
  • 总结


【单源最短路/DFS/spfa/dijkstra】2020年蓝桥杯真题之作物杂交_第1张图片


⭐️作物杂交⭐️

题目详情

作物杂交
【单源最短路/DFS/spfa/dijkstra】2020年蓝桥杯真题之作物杂交_第2张图片

解题思路

思路1:DFS,我们从目标结点开始搜索,搜索前记录所有被合成种子的父结点,以及种子的拥有情况,以及每种种子所需要的生长时间,假设我们需要合成种子是 t t t, 我们搜索 t t t的所有合成方案,也就是遍历所有的可行父结点,不妨记录遍历的父结点为 a a a b b b, 如果 a a a不存在则去合成 a a a,同理 b b b不存在就去合成 b b b, 当合成 t t t的种子都有了后,我们就将 t t t标记为 t r u e true true表示 t t t已经合成了,表示存在状态,并更新合成 t t t的最短时间 f [ t ] = m a x ( t i m e s [ a ] , t i m e s [ b ] ) + m a x ( f [ a ] + f [ b ] ) f[t]=max(times[a],times[b])+max(f[a]+f[b]) f[t]=max(times[a],times[b])+max(f[a]+f[b])

思路2:转换为最短路问题,我们可以使用一个超级原点,与所有初始存在的种子相连,并且权值为 0 0 0,这样就可以同时从多个点开始搜索, 然后我们按照 < 种子 1 , 种子 2 ,合成种子 > <种子1, {种子2 , 合成种子}> <种子1种子2,合成种子>建立边,权值就是作物生长时间,然后问题就转换为求从原点到 t t t的最短路问题,可以采用spfa,dijkstra算法解题。

源代码

思路1:DFS, java

import java.util.*;
import java.io.*;

public class Main {
  static final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  static final PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

  static final int N = 2020, INF = 0x3f3f3f3f;

  //储存种子生长时间
  static int[] w = new int[N];
  //判断种子是否存在
  static boolean[] has = new boolean[N];
  //储存合成种子x所需的种子
  static List<int[]> fa[] = new ArrayList[N];
  //记录合成某个种子合成需要的时间
  static int[] f = new int[N];
  static int n, m, k, t;
  static int dfs(int x) {
    for(int[] e : fa[x]) {
      int a = e[0];
      int b = e[1];

      if (!has[a]) dfs(a);
      if (!has[b]) dfs(b);
      
      if (has[a] && has[b]) {
        has[x] = true;
        f[x] = Math.min(f[x], Math.max(w[a], w[b]) + Math.max(f[a], f[b]));
      }
    }
    return f[x];
  }

  public static void main(String[] args) throws IOException {
    String[] ss = br.readLine().trim().split(" ");
    n = Integer.parseInt(ss[0]);
    m = Integer.parseInt(ss[1]);
    k = Integer.parseInt(ss[2]);
    t = Integer.parseInt(ss[3]);
    for (int i = 1; i <= n; i++) fa[i] = new ArrayList<>();
    Arrays.fill(f, INF);
    ss = br.readLine().trim().split(" ");
    for (int i = 0; i < n; i++) {
      w[i + 1] = Integer.parseInt(ss[i]);
      //out.print(w[i + 1] + " ");
    }
    //out.println();
    ss = br.readLine().trim().split(" ");
    for (int i = 0; i < m; i++) {
      int tmp = Integer.parseInt(ss[i]);
      has[tmp] = true;
      f[tmp] = 0;
    }

    for (int i = 0; i < k; i++) {
      ss = br.readLine().trim().split(" ");
      int a = Integer.parseInt(ss[0]);
      int b = Integer.parseInt(ss[1]);
      int c = Integer.parseInt(ss[2]);

      fa[c].add(new int[]{a, b});
    }

    out.println(dfs(t));
    out.close();
  }
}

思路2:spfa,java

import java.util.*;
import java.io.*;

public class Main {
  static final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  static final PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

  static final int N = 2020, M = (int) 3e5 + 10, INF = 0x3f3f3f3f;
  //邻接表
  static int[] h = new int[N], en = new int[M];
  static int[][] e = new int[M][2];
  //存每颗种子的成长时间
  static int[] times = new int[N];
  //距离数组
  static int[] dist = new int[N];
  //表示该点有没有在队列当中
  static boolean[] st = new boolean[N];
  //表示该种子有没有现成的
  static boolean[] has = new boolean[N];
  // 队列
  static int[] q = new int[N];
  static int n, m, k, t, idx;

  static void add(int a, int[] b) {
    e[idx] = b;
    en[idx] = h[a];
    h[a] = idx++;
  }

  static int spfa(int x) {
    //初始化距离
    Arrays.fill(dist, INF);
    //超级原点
    dist[0] = 0;
    st[0] = true;
    has[0] = true;
    //将更新过的点加入队列
    int tt = 0, hh = 0;
    q[tt++] = 0;
    while (tt != hh) {
      int t = q[hh++];
      if (hh == N) hh = 0;
      st[t] = false;
      //更新
      for (int i = h[t]; i != -1; i = en[i]) {
        int a = t;
        int b = e[i][0];
        int c = e[i][1];
        if (!has[a] || !has[b]) continue;
        has[c] = true;
        int distance = Math.max(dist[a], dist[b]) + Math.max(times[a], times[b]);

        if (dist[c] > distance) {
          dist[c] = distance;
          if (!st[c]) {
            q[tt++] = c;
            st[c] = true;
            if (tt == N) tt = 0;
          }
        }
      }
    }
    return dist[x];
  }

  public static void main(String[] args) throws IOException {
    String[] ss = br.readLine().trim().split(" ");
    n = Integer.parseInt(ss[0]);
    m = Integer.parseInt(ss[1]);
    k = Integer.parseInt(ss[2]);
    t = Integer.parseInt(ss[3]);

    Arrays.fill(h, -1);
    ss = br.readLine().trim().split(" ");
    for (int i = 1; i <= n; i++) times[i] = Integer.parseInt(ss[i - 1]);

    ss = br.readLine().trim().split(" ");

    for (int i = 0; i < m; i++) {
      int a = Integer.parseInt(ss[i]);
      has[a] = true;
      //初始化超级原点
      add(0, new int[]{0, a});
    }

    for (int i = 0; i < k; i++) {
      ss = br.readLine().trim().split(" ");
      int a = Integer.parseInt(ss[0]);
      int b = Integer.parseInt(ss[1]);
      int c = Integer.parseInt(ss[2]);
      add(a, new int[]{b, c});
      add(b, new int[]{a, c});
    }

    out.println(spfa(t));
    out.close();
  }
}

思路2:dijkstra,java

import java.util.*;
import java.io.*;

public class Main {
  static final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  static final PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

  static final int N = 2020, M = (int) 3e5 + 10, INF = 0x3f3f3f3f;
  //邻接表
  static int[] h = new int[N], en = new int[M];
  static int[][] e = new int[M][2];
  //存每颗种子的成长时间
  static int[] times = new int[N];
  //距离数组
  static int[] dist = new int[N];
  //表示该点有没有在队列当中
  static boolean[] st = new boolean[N];
  //表示该种子有没有现成的
  static boolean[] has = new boolean[N];
  // 队列
  static int[] q = new int[N];
  static int n, m, k, t, idx;

  static void add(int a, int[] b) {
    e[idx] = b;
    en[idx] = h[a];
    h[a] = idx++;
  }

  static int dijkstra(int x) {
    //优先级队列
    PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> {
      return a[0] - b[0];
    });
    //初始化距离
    Arrays.fill(dist, INF);
    dist[0] = 0;
    has[0] = true;
    pq.offer(new int[]{0, 0});

    while (!pq.isEmpty()) {
      int[] t = pq.poll();
      //out.println(t[1]);
      if (st[t[1]]) continue;
      st[t[1]] = true;
      for (int i = h[t[1]]; i != -1; i = en[i]) {
        int a = t[1];
        int b = e[i][0];
        int c = e[i][1];
        //out.println(a + " " + b + " " + c);
        if (!has[a] || !has[b]) continue;
        has[c] = true;
        int distance = Math.max(times[a], times[b]) + Math.max(dist[a], dist[b]);
        //out.println(distance);
        if (distance < dist[c]) {
          dist[c] = distance;
          pq.offer(new int[]{distance, c});
        }
      }
    }
    return dist[x];
  }

  public static void main(String[] args) throws IOException {
    String[] ss = br.readLine().trim().split(" ");
    n = Integer.parseInt(ss[0]);
    m = Integer.parseInt(ss[1]);
    k = Integer.parseInt(ss[2]);
    t = Integer.parseInt(ss[3]);

    Arrays.fill(h, -1);
    ss = br.readLine().trim().split(" ");
    for (int i = 1; i <= n; i++) times[i] = Integer.parseInt(ss[i - 1]);

    ss = br.readLine().trim().split(" ");

    for (int i = 0; i < m; i++) {
      int a = Integer.parseInt(ss[i]);
      has[a] = true;
      //初始化超级原点
      add(0, new int[]{0, a});
    }

    for (int i = 0; i < k; i++) {
      ss = br.readLine().trim().split(" ");
      int a = Integer.parseInt(ss[0]);
      int b = Integer.parseInt(ss[1]);
      int c = Integer.parseInt(ss[2]);
      add(a, new int[]{b, c});
      add(b, new int[]{a, c});
    }

    out.println(dijkstra(t));
    out.close();
  }
}

总结

图论单源最短路问题。


觉得文章写得不错的老铁们,点赞评论关注走一波!谢谢啦!

1-99

你可能感兴趣的:(#,蓝桥杯,#,数论与图论,深度优先,蓝桥杯,算法,dijkstra,spfa)