机试day11

最短路径:求图G中两个特定顶点之间最短路径长度

应用包括:求两个城市间最短行车距离等

经典算法:Dijkstra算法,将顶点集合V分成两个集合S和T

  • S:已确定的顶点集合,初始只含源点s
  • T=V-S:尚未确定的顶点集合

算法反复从集合T中选择当前源点s最近的顶点u,将u加入集合S,然后对所有从u发出的边进行松弛操作(贪心策略)

畅通工程续

题目:已知起点终点,计算最短行走距离,每组第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表城镇数目和已修建道路数目。接下来是M行道路信息,每行A、B、X表示AB间一条道路距离X。再接下来一行有两个整数S、T代表起点终点

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
#include <climits>
using namespace std;

const int MAXN = 200;
const int INF = INT_MAX;    // 无穷大

struct Edge {
    int to, length;
    Edge(int t, int l): to(t), length(l) {}
};

struct Point {
    int number, distance;
    Point(int n, int d): number(n), distance(d) {}
    bool operator< (const Point& p) const {
        return distance > p.distance;
    }
};

vector<Edge> graph[MAXN];   // 邻接表实现的图
int dis[MAXN];              // 源点到各点距离

void Dijkstra(int s) {
    priority_queue<Point> myPriorityQueue;
    dis[s] = 0;
    myPriorityQueue.push(Point(s, dis[s]));
    while (!myPriorityQueue.empty()) {
        int u = myPriorityQueue.top().number;
        myPriorityQueue.pop();
        for (int i = 0; i < graph[u].size(); i++) {
            int v = graph[u][i].to;
            int d = graph[u][i].length;
            if (dis[v] > dis[u] + d) {
                dis[v] = dis[u] + d;
                myPriorityQueue.push(Point(v, dis[v]));
            }
        }
    
    }
}

int main() {
    int n, m;
    while (cin >> n >> m) {
        memset(graph, 0, sizeof(graph));
        fill(dis, dis + n, INF);    // 距离初始化为无穷
        while (m--) {
            int from, to, length;
            cin >> from >> to >> length;
            graph[from].push_back(Edge(to, length));
            graph[to].push_back(Edge(from, length));
        }
        int s, t;
        cin >> s >> t;
        Dijkstra(s);
        if (dis[t] == INF) 
            dis[t] = -1;
        cout << dis[t] << endl;
    }
}

最短路径问题

描述

给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。

输入描述

输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。n和m为0时输入结束。 (1<n<=1000, 0<m<100000, s != t)

输出描述

输出 一行有两个数, 最短距离及其花费。

思路:在上一题的基础上增加cost,因此需要改变小于号的重载,先比较距离,如果相等再比较花费

同时需要注意有俩种满足最小路径的条件,一种是距离更小,一种是距离相等但花费更少

#include <iostream>
#include <vector>
#include <climits>
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;

const int MAXN = 1000;
const int INF = INT_MAX;

struct Edge {
    int to, length, cost;
    Edge(int t, int l, int c): to(t), length(l), cost(c) {}
};

struct Point {
    int number, distance, cost;
    Point(int n, int d, int c): number(n), distance(d), cost(c) {} 
    bool operator< (const Point& p) const {
        if (distance != p.distance)
            return distance > p.distance;
        else
            return cost > p.cost;
    }
};

vector<Edge> graph[MAXN];
int dis[MAXN], cost[MAXN];

void Dijstra(int s) {
    priority_queue<Point> myPriorityQueue;
    dis[s] = 0, cost[s] = 0;
    myPriorityQueue.push(Point(s, dis[s], cost[s]));
    while (!myPriorityQueue.empty()) {
        int u = myPriorityQueue.top().number;
        myPriorityQueue.pop();
        for (int i = 0; i < graph[u].size(); i++) {
            int v = graph[u][i].to;
            int l = graph[u][i].length;
            int c = graph[u][i].cost;
            if (dis[v] > dis[u] + l || (dis[v] == dis[u] + l && cost[v] > cost[u] + c)) {
                dis[v] = dis[u] + l;
                cost[v] = cost[u] + c;
                myPriorityQueue.push(Point(v, dis[v], cost[v]));
            }
        }
    }
}


int main() {
    int n, m;
    while (cin >> n >> m) {
        if (n == 0 && m == 0)
            break;
        memset(graph, 0, sizeof(graph));
        fill(dis, dis + n + 1, INF);
        fill(cost, cost + n + 1, INF);
        int a, b, d, p;
        while (m--) {
            cin >> a >> b >> d >> p;
            graph[a].push_back(Edge(b, d, p));
            graph[b].push_back(Edge(a, d, p));
        }
        int s, t;
        cin >> s >> t;
        Dijstra(s);
        cout << dis[t] << " " << cost[t] << endl;
    }
}
最后修改:2023 年 06 月 29 日
如果觉得我的文章对你有用,请随意赞赏