7-7 Super Mario (10 points)

Suppose there are n castles, numbered from 1 to n. Some castles are directly connected by roads, and some castles are not directly connected by roads. Mario is now preparing to start from one castle to another. It has a magic wand that can pass through a road instantly, that is, pass this road in 0 time, but the magic wand can only be used once. Mario wants to reach the destination in the shortest time, please write a program to choose a route for Mario and where to use the magic wand. Assuming that all roads are two-way, it is guaranteed to reach the destination from the starting point.

Insert picture description here
Input format:
Input the first line of 4 integers n, s, t, m, which respectively represent the number of castles (numbered from 1 to n, n does not exceed 10000), the starting point s where Mario is and the ending point t that you want to go, between the castles The number of roads. In the next m lines, each line contains 3 positive integers a, b, and c, indicating that there is a road directly connected between castle a and castle b, and it takes c minutes to pass the road.

Output format: The
output is 2 integers separated by spaces, the first integer is the shortest time required for Mario to get from the starting point to the destination; the second integer represents the place where the magic wand is used, that is, the castle number, if more than one is possible The location with the smallest number will be output.

Input sample:

4 1 4 4
1 2 9
2 4 1
1 3 3
3 4 5

Sample output:

1 1

I was stuck in the data range of the last two test points for a long time. Not done independently, ask others
AC code 1: Find the shortest path of s and the shortest path of t once, and then enumerate the edges. If the two end points of this edge can reach s and t respectively, it means that there is a way to go from s to t through this edge. Then the minimum value of this path is the shortest path from s to one end of this side + t the shortest path to the other end. It is necessary to remember this adjacency list and initialization, because I rarely write this, but I have seen
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;

typedef struct {
    
    
    int u, v; //每条边的起点和终点
} Edge;

typedef long long ll;
const ll inf = 1e12;
const int N = 1e4 + 10, M = 1e8 + 10;//分别为顶点数和边数
bool vis[N] = {
    
    false};
ll diss[N], dist[N]; //diss表示起点s到其他各点的距离,dist表示终点t到其他各点的距离
 //h表示从某顶点出发的第一条边的编号,e为该条边的终点编号,
 //w为该条边的权值,ne存储从该顶出发的下一条边的编号,idx为第几条边
int h[N], e[M], w[M], ne[M], idx;
int n, m, s, t; //顶点数 边数 起点 终点
Edge edge[M]; //存储每一条边的信息

void add(int a, int b, int c) {
    
     //邻接表(头插法)存储边信息
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

void spfa(ll dis[], int u) {
    
     //最短路算法spfa
    for (int i = 1; i <= n; i++) {
    
    
        dis[i] = inf;
        vis[i] = false;
    }
    queue<int> qe;
    qe.push(u);
    dis[u] = 0;
    vis[u] = true;
    while (!qe.empty()) {
    
    
        int x = qe.front();
        qe.pop();
        vis[x] = false;
        for (int i = h[x]; i != -1; i = ne[i]) {
    
    
            int j = e[i];
            if (dis[j] > dis[x] + w[i]) {
    
    
                dis[j] = dis[x] + w[i];
                if (!vis[j]) {
    
    
                    qe.push(j);
                    vis[j] = 1;
                }
            }
        }
    }
}

int main() {
    
    
    scanf("%d %d %d %d", &n, &s, &t, &m);
    memset(h, -1, sizeof(h)); //初始时,每个顶点的第一条边的编号都设为-1,表示没有边
    for (int i = 0; i < m; i++) {
    
     //输入每条边的信息
        int a, b, c;
        scanf("%d %d %d", &a, &b, &c);
        add(a, b, c), add(b, a, c); //双向存储边信息
        edge[2 * i].u = a, edge[2 * i].v = b;//正向存储每条边的起点和终点
        edge[2 * i + 1].u = b, edge[2 * i + 1].v = a;//反向存储每条边的起点和终点
    }
    spfa(diss, s);//从起点s出发的单源最短路
    spfa(dist, t);//从终点t出发的单源最短路
    ll minx = inf;
    int pos;
    for (int i = 0; i < 2 * m; i++) {
    
    
        int a = edge[i].u, b = edge[i].v;
        if (diss[a] + dist[b] < minx) {
    
     //寻找最小值
            minx = diss[a] + dist[b];
            pos = a;
        } else if (diss[a] + dist[b] == minx && a < pos) {
    
     //最小值相同时,寻找最小编号
            pos = a;
        }
    }
    printf("%lld %d", minx, pos);
    return 0;
}
Code 1C language version
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    
    
    int u, v; //每条边的起点和终点
} Edge;

typedef long long ll;
const ll inf = 1e12;
//M的大小不能为1e8及以上,我的不行,提示内存超限!!!!
const int N = 1e4 + 10, M = 1e7 + 1000; //分别为顶点数和边数
int q[N];
int vis[N] = {
    
    0};
ll diss[N],
    dist[N]; // diss表示起点s到其他各点的距离,dist表示终点t到其他各点的距离
             // h表示从某顶点出发的第一条边的编号,e为该条边的终点编号,
             // w为该条边的权值,ne存储从该顶出发的下一条边的编号,idx为第几条边
int h[N], e[M], w[M], ne[M], idx;
int n, m, s, t; //顶点数 边数 起点 终点
Edge edge[M];   //存储每一条边的信息

void add(int a, int b, int c) {
    
     //邻接表(头插法)存储边信息
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

void spfa(ll dis[], int u) {
    
     //最短路算法spfa
    for (int i = 1; i <= n; i++) {
    
    
        dis[i] = inf;
        vis[i] = 0;
    }
    int head = 0, rear = 0;
    q[rear++] = u;
    dis[u] = 0;
    vis[u] = 1;
    while (head != rear) {
    
    
        int x = q[head++];
        vis[x] = 0;
        for (int i = h[x]; i != -1; i = ne[i]) {
    
    
            int j = e[i];
            if (dis[j] > dis[x] + w[i]) {
    
    
                dis[j] = dis[x] + w[i];
                if (!vis[j]) {
    
    
                    q[rear++] = j;
                    vis[j] = 1;
                }
            }
        }
    }
}

int main() {
    
    
    scanf("%d %d %d %d", &n, &s, &t, &m);
    memset(h, -1,sizeof(h)); //初始时,每个顶点的第一条边的编号都设为-1,表示没有边
    for (int i = 0; i < m; i++) {
    
     //输入每条边的信息
        int a, b, c;
        scanf("%d %d %d", &a, &b, &c);
        add(a, b, c), add(b, a, c);           //双向存储边信息
        edge[2 * i].u = a, edge[2 * i].v = b; //正向存储每条边的起点和终点
        edge[2 * i + 1].u = b, edge[2 * i + 1].v = a; //反向存储每条边的起点和终点
    }
    spfa(diss, s); //从起点s出发的单源最短路
    spfa(dist, t); //从终点t出发的单源最短路
    ll minx = inf;
    int pos;
    for (int i = 0; i < 2 * m; i++) {
    
    
        int a = edge[i].u, b = edge[i].v;
        if (diss[a] + dist[b] < minx) {
    
     //寻找最小值
            minx = diss[a] + dist[b];
            pos = a;
        } else if (diss[a] + dist[b] == minx && a < pos) {
    
     //最小值相同时,寻找最小编号
            pos = a;
        }
    }
    printf("%lld %d", minx, pos);
    return 0;
}
AC code 2: Hierarchical graph, emmm, it is still very awkward, after the completion, a total of two graphs, using the shortest path algorithm once, not the code I wrote.
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int path[N], h[N], e[N], w[N], ne[N], idx, d[N], q[N], n;
bool st[N];
void add(int a, int b, int c) {
    
    
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void spfa(int s) {
    
    
    memset(d, 0x3f, sizeof d);
    int hh = 0, tt = 0;
    q[tt++] = s;
    d[s] = 0;
    st[s] = 1;
    while (hh != tt) {
    
    
        int t = q[hh++];
        st[t] = 0;
        for (int i = h[t]; ~i; i = ne[i]) {
    
    
            int j = e[i];
            if (d[j] > d[t] + w[i]) {
    
    
                d[j] = d[t] + w[i];
                path[j] = t;
                if (!st[j]) {
    
    
                    q[tt++] = j;
                    st[j] = 1;
                }
            } else if (n <= 10 && d[j] == d[t] + w[i] && path[j] > t)
                path[j] = t;
        }
    }
}
int main() {
    
    
    memset(h, -1, sizeof h);
    int s, t, m;
    scanf("%d%d%d%d", &n, &s, &t, &m);
    while (m--) {
    
    
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c), add(b, a, c), add(a, b + n, 0), add(b, a + n, 0),
            add(a + n, b + n, c), add(b + n, a + n, c);
    }
    spfa(s);
    int x = t + n;
    while (x > n)
        x = path[x];
    printf("%d %d", d[t + n], x);
    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45845039/article/details/113743152