百度之星BD202301 公园,使用Java
小度当前所在景点编号为 T,从一个景点到附近的景点需要消耗的体力是 TE,
而度度熊所在景点编号为 F ,移动消耗为 FE。
如果小度和度度熊一块移动(即在相同位置向相同方向移动),每一步他俩的总消耗将会减少 S。
求他俩到景点 N 时,所需要的总消耗最少是多少?
输入格式:
第一行三个数值,TE,FE,S ,分别代表小度移动消耗值,度度熊移动消耗值,一起移动的消耗减少值。1≤TE,FE,S≤40000, S ≤TE+FE。
第二行四个数值,T,F,N,M,分别代表小度出发点,度度熊出发点,目标节点,总路径数。1 ≤ T,F,N,M ≤40000
接下来 MM 行,每行两个整数 X,Y,代表连通的两个景点。1≤X,Y≤N。
输出格式:
一个整数,即总消耗最小值。如果不能到达 N , 输出-1。
样例
输入:
4 4 3
1 2 8 8
1 4
2 3
3 4
4 7
2 5
5 6
6 8
7 8
输出:
22
知识点:
邻接表
bfs算法
废话少说上代码
package example;
import java.util.ArrayList;
import java.util.Scanner;
public class bd01 {
public static final int n = 40010;
public static int TE, FE, S;
public static int T, F, N, M;
//创建动态数组v,大小n
public static ArrayList<Integer>[] v = new ArrayList[n]; // 邻接表v,存储图的边信息
//创建二维数组d,0—>小度,1—>熊,2—>终点
public static int[][] d = new int[3][n]; // 小度、度度熊、终点到每个点的最短距离
public static void bfs(int[] dist, int src) // 求起点src到每个点的最短距离
{
/* bfs求最短路的模板 */
int[] q = new int[n];//储存待处理节点
// 初始化为-1,表示src不能直接到达这些节点
for (int i = 1; i <= N; i++) dist[i] = -1;
//表示队列头部,-1表示队列为空
int hh = -1;
//表示队列尾部,0表示队列中有一个元素
int tt = 0;
//设起点到自己距离0
dist[src] = 0;
//将起点 src 加入队列 q 中,同时更新 hh 的值,表示队列中有一个元素
q[++hh] = src;
while (hh <= tt)
{
//取出头部节点并将hh+1,表示取出一个节点
int head = q[hh++];
//遍历当前节点head的邻居节点
for (int x : v[head])
{
//如果邻居节点的距离尚未确定
if (dist[x] == -1)
{
//将节点 x 的距离更新为当前节点 head 的距离加 1
// 表示从起点 src 经过节点 head 到达节点 x 的距离
dist[x] = dist[head] + 1;
//将节点 x 加入队列 q 的尾部,并更新 tt 的值,表示队列中多了一个元素
q[++tt] = x;
}
}
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
TE = scanner.nextInt();
FE = scanner.nextInt();
S = scanner.nextInt();
T = scanner.nextInt();
F = scanner.nextInt();
N = scanner.nextInt();
M = scanner.nextInt();
for (int i = 1; i <= N; i++) {
v[i] = new ArrayList<>();
}
for (int i = 0; i < M; i++)
{
int a = scanner.nextInt();
int b = scanner.nextInt();
v[a].add(b);
v[b].add(a);
}
// 分别计算T、F、N到所有点的最短路径
bfs(d[0], T);
bfs(d[1], F);
bfs(d[2], N);
long ans = Long.MAX_VALUE;
for (int i = 1; i <= N; i++)
{
// 这里要判断是否等于-1。如果等于-1,说明当前汇合点i不能到达T、F、N中的某个点
if (d[0][i] != -1 && d[1][i] != -1 && d[2][i] != -1)
{
//创建一个名为distance的长整数变量,储存从i到达三个目标节点的距离之和
//(long)强制类型转换,防止计算时溢出
long distance = (long) d[0][i] * TE + (long) d[1][i] * FE + (long) d[2][i] * (TE + FE - S);
ans = Math.min(ans, distance);
}
}
if (ans == Long.MAX_VALUE) System.out.println(-1);
else System.out.println(ans);
}
}
其他:
最后细说一下main
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
TE = scanner.nextInt();
FE = scanner.nextInt();
S = scanner.nextInt();
T = scanner.nextInt();
F = scanner.nextInt();
N = scanner.nextInt();
M = scanner.nextInt();
for (int i = 1; i <= N; i++) {
v[i] = new ArrayList<>();
}
for (int i = 0; i < M; i++)
{
int a = scanner.nextInt();
int b = scanner.nextInt();
v[a].add(b);
v[b].add(a);
}
// 分别计算T、F、N到所有点的最短路径
bfs(d[0], T);
bfs(d[1], F);
bfs(d[2], N);
long ans = Long.MAX_VALUE;
for (int i = 1; i <= N; i++)
{
// 这里要判断是否等于-1。如果等于-1,说明当前汇合点i不能到达T、F、N中的某个点
if (d[0][i] != -1 && d[1][i] != -1 && d[2][i] != -1)
{
//创建一个名为distance的长整数变量,储存从i到达三个目标节点的距离之和
//(long)强制类型转换,防止计算时溢出
long distance = (long) d[0][i] * TE + (long) d[1][i] * FE + (long) d[2][i] * (TE + FE - S);
ans = Math.min(ans, distance);
}
}
if (ans == Long.MAX_VALUE) System.out.println(-1);
else System.out.println(ans);
}
-
程序使用循环读取输入数据,构建图的邻接表。对于每个边,程序读取两个整数
a
和b
,表示两个节点之间有一条边,然后将这条边添加到对应的ArrayList
中。 -
接下来,程序调用
bfs
方法三次,分别计算从T
、F
、N
到所有其他节点的最短距离,分别存储在d[0]
、d[1]
、d[2]
数组中。 -
最后,程序使用一个循环遍历所有节点,计算满足条件的节点的距离之和,并找出最小的距离之和,将其存储在
ans
变量中。 -
long distance = (long) d[0][i] * TE + (long) d[1][i] * FE + (long) d[2][i] * (TE + FE - S);
:首先,代码创建一个名为distance
的长整数(long
)变量,用于存储从节点i
到达三个目标节点的距离之和。这里使用强制类型转换(long)
将整数值转换为长整数,以确保在计算距离之和时不会发生溢出。d[0][i] * TE
表示从节点i
到目标节点T
的距离乘以TE
。d[1][i] * FE
表示从节点i
到目标节点F
的距离乘以FE
。d[2][i] * (TE + FE - S)
表示从节点i
到目标节点N
的距离乘以(TE + FE - S)
。 -
ans = Math.min(ans, distance);
接下来,代码比较当前的最小距离ans
与计算得到的distance
,并将较小的值存储回ans
中。这样,ans
会始终保持为已经计算过的路径中的最小距离。 -
最后,程序根据
ans
的值输出结果,如果ans
仍然等于Long.MAX_VALUE
,则输出-1
,否则输出ans
的值。
最后:
在网站提交时,public class类的名字一定要写Main或main