使用c语言实现这段代码:输入格式: 输入第一行是三个正整数 N、M 和 K,表示魔都地铁有 N 个车站 (1 ≤ N ≤ 200),M 条线路 (1 ≤ M ≤ 1500),最短距离每超过 K 公里 (1 ≤ K ≤ 106),加 1 元车费。 接下来 M 行,每行由以下格式组成: <站点1><空格><距离><空格><站点2><空格><距离><空格><站点3> ... <站点X-1><空格><距离><空格><站点X> 其中站点是一个 1 到 N 的编号;两个站点编号之间的距离指两个站在该线路上的距离。两站之间距离是一个不大于 106 的正整数。一条线路上的站点互不相同。 注意:两个站之间可能有多条直接连接的线路,且距离不一定相等。 再接下来有一个正整数 Q (1 ≤ Q ≤ 200),表示森森尝试从 Q 个站点出发。 最后有 Q 行,每行一个正整数 **Xi**,表示森森尝试从编号为 Xi 的站点出发。 输出格式: 对于森森每个尝试的站点,输出一行若干个整数,表示能够到达的站点编号。站点编号从小到大排序。
时间: 2024-03-09 16:49:25 浏览: 32
以下是使用C语言实现的代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#define MAX_N 200
#define MAX_M 1500
#define MAX_DIST 1000000 // 10^6
typedef struct {
int to; // 目标节点
int dist; // 边的权值
int next; // 指向下一条边的指针
} Edge;
Edge edge[MAX_M * 2 + 1]; // 边集数组
int head[MAX_N + 1]; // 邻接表头
int dist[MAX_N + 1]; // 从起点到各个节点的最短距离
int cnt[MAX_N + 1]; // 记录从起点到每个节点的最短路径条数
int vis[MAX_N + 1]; // 标记数组,标记节点是否已经访问过
int queue[MAX_N + 1]; // 队列,用于 BFS
int q[MAX_N + 1]; // 记录要查询的站点编号
int n, m, k, q_cnt, edge_cnt;
// 添加一条边,起点为 from,终点为 to,边权为 dist
void add_edge(int from, int to, int dist) {
edge[edge_cnt].to = to;
edge[edge_cnt].dist = dist;
edge[edge_cnt].next = head[from];
head[from] = edge_cnt;
edge_cnt++;
}
// 使用 Dijkstra 算法计算从起点到各个节点的最短路径
void dijkstra(int start) {
memset(vis, 0, sizeof(vis)); // 初始化标记数组
memset(dist, 0x3f, sizeof(dist)); // 初始化距离数组,初始值为无穷大
memset(cnt, 0, sizeof(cnt)); // 初始化计数数组
dist[start] = 0; // 起点到自身的距离为 0
cnt[start] = 1; // 起点到自身的最短路径条数为 1
for (int i = 0; i < n - 1; i++) {
int min_dist = INT_MAX, u;
// 选择距离起点最近的未访问节点
for (int j = 1; j <= n; j++) {
if (!vis[j] && dist[j] < min_dist) {
min_dist = dist[j];
u = j;
}
}
vis[u] = 1; // 标记节点为已访问
// 更新与节点 u 相邻的节点的距离和最短路径条数
for (int j = head[u]; j != -1; j = edge[j].next) {
int v = edge[j].to; // 相邻节点 v
if (dist[u] + edge[j].dist < dist[v]) { // 更新最短路径
dist[v] = dist[u] + edge[j].dist;
cnt[v] = cnt[u]; // 更新最短路径条数
}
else if (dist[u] + edge[j].dist == dist[v]) { // 如果有多条最短路径
cnt[v] += cnt[u]; // 累加最短路径条数
}
}
}
}
// 使用 BFS 计算从起点到各个节点的最短路径
void bfs(int start) {
memset(vis, 0, sizeof(vis)); // 初始化标记数组
memset(dist, 0x3f, sizeof(dist)); // 初始化距离数组,初始值为无穷大
dist[start] = 0; // 起点到自身的距离为 0
vis[start] = 1; // 标记起点为已访问
int front = 0, rear = 0;
queue[rear++] = start; // 将起点入队
while (front != rear) {
int u = queue[front++]; // 出队一个节点
for (int j = head[u]; j != -1; j = edge[j].next) {
int v = edge[j].to; // 相邻节点 v
if (dist[u] + edge[j].dist <= k) { // 如果可以直接到达
if (dist[u] + edge[j].dist < dist[v]) { // 更新最短路径
dist[v] = dist[u] + edge[j].dist;
vis[v] = 1; // 标记节点为已访问
queue[rear++] = v; // 将节点入队
}
}
}
}
}
int main() {
memset(head, -1, sizeof(head)); // 初始化邻接表头,-1 表示该节点没有边
scanf("%d %d %d", &n, &m, &k);
for (int i = 0; i < m; i++) {
int x, y, d;
scanf("%d", &x);
for (int j = 1; j < x; j++) { // 从第 2 个站点开始循环
scanf("%d %d", &y, &d);
add_edge(x, y, d);
add_edge(y, x, d); // 无向图需要添加反向边
}
}
scanf("%d", &q_cnt);
for (int i = 0; i < q_cnt; i++) {
scanf("%d", &q[i]);
}
// 计算从所有站点到其他站点的最短路径
for (int i = 1; i <= n; i++) {
dijkstra(i);
for (int j = 1; j <= n; j++) {
if (i != j) { // 不计算自身到自身的路径
int d = dist[j];
if (d <= k) { // 如果可以直接到达
add_edge(i, j, d); // 添加一条边
add_edge(j, i, d); // 无向图需要添加反向边
}
}
}
}
// 查询能够到达的站点编号
for (int i = 0; i < q_cnt; i++) {
bfs(q[i]);
int first = 1;
for (int j = 1; j <= n; j++) {
if (vis[j]) { // 如果能够到达
if (first) {
printf("%d", j);
first = 0;
}
else {
printf(" %d", j);
}
}
}
printf("\n");
}
return 0;
}
```
这个代码使用了邻接表来存储图,使用了 Dijkstra 算法和 BFS 算法来计算最短路径。同时,为了减少计算量,我们预处理了每个站点到其他站点的最短路径,并把满足一定条件的路径添加成边,这样就可以大幅减少计算量,提高程序的效率。