时间限制
200 ms
内存限制
64 MB
题目描述:
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。
第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。
输出格式:
第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。
输入样例:
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2
输出样例:
2 60
0 1 3
先输出 最短路的条数 和 最短路上能最多召集多少人
在输出最短路上最多能召集人数的路径的点
emmmmmmm
基础dijstra的模板 只不过加了人数 条数 路径
在更新最短路的同时 人数 条数 路径都需要更新
还有 最短路相同时 条数需要更新 但路径更新需要看人数来更新
注: java选手可能要多交几发才能a
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;
public class Main
{
static int inf = 0x3f3f3f3f;
static int N = 500;
// 存储 i 这个点上的志愿者
static int shu[] = new int[N + 10];
// 存储地图
static int map[][] = new int[N + 10][N + 10];
// 存储 S - i 的最短路径长度
static int d[] = new int[N + 10];
// 存储是否被用过
static boolean vis[] = new boolean[N + 10];
// 存储 S -> i 的最短路 的 条数
static int num[] = new int[N + 10];
// 存储 S -> i 的最短路 上的 最多召集人数
static int sum[] = new int[N + 10];
// 存储 是由 pre[i] -> i 的 也就是 i 这个点是从哪个点来的
static int pre[] = new int[N + 10];
static int S, D;
static void print(int u)
{
if (u == S)
{
out.print(u);
return;
}
print(pre[u]);
out.print(" " + u);
}
public static void main(String[] args) throws IOException
{
int n = ini();
int m = ini();
S = ini();
D = ini();
for (int i = 0; i < n; i++)
shu[i] = ini();
// 初始化地图
for (int i = 0; i < n; i++)
Arrays.fill(map[i], inf);
// 地图路径赋值
while (m-- > 0)
{
int u = ini();
int v = ini();
int w = ini();
map[u][v] = map[v][u] = Math.min(map[u][v], w);
}
// 初始化 S 到各点的距离
Arrays.fill(d, inf);
// S -> S 的距离为0
d[S] = 0;
// S -> S 只有一种路径选择
num[S] = 1;
// S -> S 最多召集的人数为 S这个点上的人数
sum[S] = shu[S];
for (int i = 0; i < n; i++)
{
// 寻找与起点最短距离的点
int t = -1;
for (int j = 0; j < n; j++)
{
if (!vis[j] && (t == -1 || d[t] > d[j]))
t = j;
}
// 标记该点的最短距离已经确定了 然后用确定的点更新其他点的最短距离
vis[t] = true;
// 用已经确定了的最短距离的点来更新到其他点的最短距离
for (int j = 0; j < n; j++)
{
// 如果 起点到j的距离 比 起点到t的距离加上t到j的距离 远时
// 那么就要更新所有值
if (d[j] > d[t] + map[t][j])
{
// 距离更新
d[j] = d[t] + map[t][j];
// 人数更新
sum[j] = sum[t] + shu[j];
// 条数更新
num[j] = num[t];
// 当前从哪个点来的更新
pre[j] = t;
}
// 如果 起点到j的距离 比 起点到t的距离加上t到j的距离 相等
else if (d[j] == d[t] + map[t][j])
{
// 如果 当前从起点到j召集的人数 比 起点到t点的召集的人数 多时
// 需要更新人数 和 当前从哪个点来
if (sum[j] < sum[t] + shu[j])
{
sum[j] = sum[t] + shu[j];
pre[j] = t;
}
// 条数增加
num[j] += num[t];
}
}
}
// 输出 条数 以及 人数
out.println(num[D] + " " + sum[D]);
// 递归打印路径
print(D);
out.flush();
out.close();
}
static StreamTokenizer sc = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter out = new PrintWriter(System.out);
static int ini() throws IOException
{
sc.nextToken();
return (int) sc.nval;
}
static String ins() throws IOException
{
sc.nextToken();
return sc.sval;
}
}
如果有说错的 或者 不懂的 尽管提 嘻嘻
一起进步!!!