⭐️前面的话⭐️
本篇文章介绍来自2020年蓝桥杯真题之作物杂交,考察算法DFS,BFS,SPFA,dijkstra,展示语言java(c++代码后续更新)。
博客主页:未见花闻的博客主页
欢迎关注点赞收藏⭐️留言
本文由未见花闻原创,CSDN首发!
首发时间:2023年4月6日
✉️坚持和努力一定能换来诗与远方!
推荐书籍:《算法》,《算法导论》
参考在线编程网站:牛客网力扣
博主的码云gitee,平常博主写的程序代码都在里面。
博主的github,平常博主写的程序代码都在里面。
作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!
思路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();
}
}
图论单源最短路问题。