• [一本通学习笔记] 最短路径


    最短路径常用算法有Dijkstra和SPFA。SPFA支持负数权重,但容易被毒瘤数据卡。
    想让SPFA跑快点可以加入一个小优化:用deque代替queue,然后在Push的时候分类,如果比当前front的dis要小就Push Front,否则Push Back。
    最短路计数和次短路问题仿照普通DP处理即可。次短路中严格非严格注意区别对待。
    建模方面主要考虑分层图等常见技巧。处理实际问题时可能结合二分答案或者枚举进行。

    10074. 「一本通 3.2 例 3」架设电话线

    #include <bits/stdc++.h>
    using namespace std;
    const int MAX_NODE = 100005;
    const int MAX_EDGE = 1000005;
    template <class T>
    class Graph_SP {  // 解决单源最短路径问题
    public:
        vector<pair<int, T> > G[MAX_NODE];
        int d[MAX_NODE], v[MAX_NODE], f[MAX_NODE];
        T t[MAX_NODE];                     // 距离表与访问标识表
        void make(int t1, int t2, T t3) {  // 造边(有向)
            G[t1].push_back(make_pair(t2, t3));
        }
        void reset_graph(int n) {  // 用于清除图邻接表
            for (int i = 0; i <= n; i++) G[i].clear();
        }
        void reset_solver(int n) {  // 对距离表与访问标识表的清除 如果改变了类型,该函数可能需要重写!
            memset(d, 0x3f, sizeof d);
            memset(v, 0x00, sizeof v);
            memset(f, 0x00, sizeof f);
        }
        void solveSPFA(int v0, int n) {  // 执行主计算任务(使用SPFA)
            queue<int> q;
            reset_solver(n);  // 自动调用对距离表与访问标识表的清除
            // d[0]=0;
            d[v0] = 0;
            v[v0] = 1;
            q.push(v0);
            while (q.size()) {
                int p = q.front();
                q.pop();
                v[p] = 0;
                for (int i = 0; i < G[p].size(); i++) {
                    int x = G[p][i].first;  // x为当前枚举边的终点,
                    T y = G[p][i].second;   // y为当前枚举边的权值
                    if (d[x] > d[p] + y) {
                        d[x] = d[p] + y;
                        t[x] = y;
                        f[x] = p;
                        if (!v[x])
                            q.push(x);
                    }
                }
            }
        }
    };
    Graph_SP<int> g;
    int n, m, k;
    struct Edge {
        int u, v, w;
        bool operator<(const Edge &b) { return w < b.w; }
    } e[MAX_EDGE];
    int check(int lim) {
        g.reset_graph(n);
        for (int i = 1; i <= m; i++) {
            g.make(e[i].u, e[i].v, (e[i].w > lim));
            g.make(e[i].v, e[i].u, (e[i].w > lim));
        }
        g.solveSPFA(1, n);
        return g.d[n];
    }
    int main() {
        cin >> n >> m >> k;
        for (int i = 1; i <= m; i++) {
            int u, v, w;
            cin >> u >> v >> w;
            e[i].u = u;
            e[i].v = v;
            e[i].w = w;
        }
        sort(e + 1, e + m + 1);
        int l = 0, r = 1e+9;
        while (r > l) {
            int mid = (l + r) >> 1;
            if (check(mid) > k)
                l = mid + 1;
            else
                r = mid;
        }
        cout << (l >= 1e+9 ? -1 : l) << endl;
    }
    

    10075. 「一本通 3.2 练习 1」农场派对

    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAX_NODE = 100005;
    const int MAX_EDGE = 200005;
    
    template <class T>
    class Graph_SP {  // 解决单源最短路径问题
    public:
        vector<pair<int, T> > G[MAX_NODE];
        int d[MAX_NODE], v[MAX_NODE];           // 距离表与访问标识表
        void make_edge(int t1, int t2, T t3) {  // 造边(有向)
            G[t1].push_back(make_pair(t2, t3));
        }
        void reset_graph(int n) {  // 用于清除图邻接表
            for (int i = 0; i <= n; i++) G[i].clear();
        }
        void reset_solver(int n) {  // 对距离表与访问标识表的清除 如果改变了类型,该函数可能需要重写!
            memset(d, 0x3f, sizeof d);
            memset(v, 0x00, sizeof v);
        }
        void solveSPFA(int v0, int n) {  // 执行主计算任务(使用SPFA)
            queue<int> q;
            reset_solver(n);  // 自动调用对距离表与访问标识表的清除
            d[v0] = 0;
            v[v0] = 1;
            q.push(v0);
            while (q.size()) {
                int p = q.front();
                q.pop();
                v[p] = 0;
                for (int i = 0; i < G[p].size(); i++) {
                    int x = G[p][i].first;  // x为当前枚举边的终点,
                    T y = G[p][i].second;   // y为当前枚举边的权值
                    if (d[x] > d[p] + y) {
                        d[x] = d[p] + y;
                        if (!v[x])
                            q.push(x);
                    }
                }
            }
        }
    };
    Graph_SP<int> g1, g2;
    int n, m, x, u, v, w;
    
    int main() {
        cin >> n >> m >> x;
        for (int i = 1; i <= m; i++) {
            cin >> u >> v >> w;
            g1.make_edge(u, v, w);
            g2.make_edge(v, u, w);
        }
        g1.solveSPFA(x, n);
        g2.solveSPFA(x, n);
        int ans = 0;
        for (int i = 1; i <= n; i++) {
            ans = max(ans, g1.d[i] + g2.d[i]);
        }
        cout << ans << endl;
    }
    

    10076. 「一本通 3.2 练习 2」Roadblocks

    #include <bits/stdc++.h>
    using namespace std;
    const int MAX_NODE = 5005;
    const int MAX_EDGE = 200005;
    template <class T>
    class Graph_SP {  // 解决单源最短路径问题
    public:
        vector<pair<int, T> > G[MAX_NODE];
        int d[MAX_NODE], v[MAX_NODE], s[MAX_NODE];  // 距离表与访问标识表
        void make_edge(int t1, int t2, T t3) {      // 造边(有向)
            G[t1].push_back(make_pair(t2, t3));
        }
        void reset_graph(int n) {  // 用于清除图邻接表
            for (int i = 0; i <= n; i++) G[i].clear();
        }
        void reset_solver(int n) {  // 对距离表与访问标识表的清除 如果改变了类型,该函数可能需要重写!
            memset(d, 0x3f, sizeof d);
            memset(s, 0x3f, sizeof d);
            memset(v, 0x00, sizeof v);
        }
        void solveSPFA(int v0, int n) {  // 执行主计算任务(使用SPFA)
            queue<int> q;
            reset_solver(n);  // 自动调用对距离表与访问标识表的清除
            d[v0] = 0;
            v[v0] = 1;
            q.push(v0);
            while (q.size()) {
                int p = q.front();
                q.pop();
                v[p] = 0;
                for (int i = 0; i < G[p].size(); i++) {
                    int x = G[p][i].first;  // x为当前枚举边的终点,
                    T y = G[p][i].second;   // y为当前枚举边的权值
                    if (d[x] > d[p] + y) {
                        s[x] = d[x];
                        d[x] = d[p] + y;
                        if (!v[x])
                            q.push(x), v[x] = 1;
                    }
                    if (s[x] > d[p] + y && d[p] + y != d[x]) {
                        s[x] = d[p] + y;
                        if (!v[x])
                            q.push(x), v[x] = 1;
                    }
                    if (s[x] > s[p] + y && s[p] + y != d[x]) {
                        s[x] = s[p] + y;
                        if (!v[x])
                            q.push(x), v[x] = 1;
                    }
                }
            }
        }
    };
    Graph_SP<int> g;
    int n, m, u, v, w;
    
    int main() {
        cin >> n >> m;
        for (int i = 1; i <= m; i++) {
            cin >> u >> v >> w;
            g.make_edge(u, v, w);
            g.make_edge(v, u, w);
        }
        g.solveSPFA(1, n);
        cout << g.s[n] << endl;
    }
    

    10078. 「一本通 3.2 练习 4」新年好

    #include <bits/stdc++.h>
    using namespace std;
    const int MAX_NODE = 100005;
    const int MAX_EDGE = 1000005;
    template <class T>
    class Graph_SP {  // 解决单源最短路径问题
    public:
        vector<pair<int, T> > G[MAX_NODE];
        int d[MAX_NODE], v[MAX_NODE];           // 距离表与访问标识表
        void make_edge(int t1, int t2, T t3) {  // 造边(有向)
            G[t1].push_back(make_pair(t2, t3));
        }
        void reset_graph(int n) {  // 用于清除图邻接表
            for (int i = 0; i <= n; i++) G[i].clear();
        }
        void reset_solver(int n) {  // 对距离表与访问标识表的清除 如果改变了类型,该函数可能需要重写!
            memset(d, 0x3f, sizeof d);
            memset(v, 0x00, sizeof v);
        }
        void solveSPFA(int v0, int n) {  // 执行主计算任务(使用SPFA)
            queue<int> q;
            reset_solver(n);  // 自动调用对距离表与访问标识表的清除
            d[v0] = 0;
            v[v0] = 1;
            q.push(v0);
            while (q.size()) {
                int p = q.front();
                q.pop();
                v[p] = 0;
                for (int i = 0; i < G[p].size(); i++) {
                    int x = G[p][i].first;  // x为当前枚举边的终点,
                    T y = G[p][i].second;   // y为当前枚举边的权值
                    if (d[x] > d[p] + y) {
                        d[x] = d[p] + y;
                        if (!v[x])
                            q.push(x), v[x] = 1;
                    }
                }
            }
        }
    };
    
    Graph_SP<int> g[6];
    int n, m, p[6], u, v, w;
    int perm[6] = { 0, 1, 2, 3, 4, 5 };
    
    int main() {
        cin >> n >> m >> p[1] >> p[2] >> p[3] >> p[4] >> p[5];
        p[0] = 1;
        for (int i = 1; i <= m; i++) {
            cin >> u >> v >> w;
            for (int j = 0; j < 6; j++) g[j].make_edge(u, v, w), g[j].make_edge(v, u, w);
        }
        for (int i = 0; i < 6; i++) {
            g[i].solveSPFA(p[i], n);
        }
        int ans = 1e+9;
        while (next_permutation(perm + 1, perm + 6)) {
            int sum = 0;
            for (int i = 1; i < 6; i++) sum += g[perm[i - 1]].d[p[perm[i]]];
            ans = min(ans, sum);
        }
        cout << ans << endl;
    }
    

    10081. 「一本通 3.2 练习 7」道路和航线

    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAX_NODE = 100005;
    const int MAX_EDGE = 1000005;
    template <class T>
    class Graph_SP {  // 解决单源最短路径问题
    public:
        vector<pair<int, T> > G[MAX_NODE];
        int d[MAX_NODE], v[MAX_NODE];           // 距离表与访问标识表
        void make_edge(int t1, int t2, T t3) {  // 造边(有向)
            G[t1].push_back(make_pair(t2, t3));
        }
        void reset_graph(int n) {  // 用于清除图邻接表
            for (int i = 0; i <= n; i++) G[i].clear();
        }
        void reset_solver(int n) {  // 对距离表与访问标识表的清除 如果改变了类型,该函数可能需要重写!
            memset(d, 0x3f, sizeof d);
            memset(v, 0x00, sizeof v);
        }
        void solveSPFA(int v0, int n) {  // 执行主计算任务(使用SPFA)
            deque<int> q;
            reset_solver(n);  // 自动调用对距离表与访问标识表的清除
            d[v0] = 0;
            v[v0] = 1;
            q.push_front(v0);
            while (q.size()) {
                int p = q.front();
                q.pop_front();
                v[p] = 0;
                for (int i = 0; i < G[p].size(); i++) {
                    int x = G[p][i].first;  // x为当前枚举边的终点,
                    T y = G[p][i].second;   // y为当前枚举边的权值
                    if (d[x] > d[p] + y) {
                        d[x] = d[p] + y;
                        if (!v[x]) {
                            v[x] = 1;
                            if (!q.empty() && d[x] < d[q.front()])
                                q.push_front(x);
                            else
                                q.push_back(x);
                        }
                    }
                }
            }
        }
    };
    
    int n, m, p, s, u, v, w;
    Graph_SP<int> g;
    
    int main() {
        ios::sync_with_stdio(false);
        cin >> n >> m >> p >> s;
        for (int i = 1; i <= m; i++) {
            cin >> u >> v >> w;
            g.make_edge(u, v, w);
            g.make_edge(v, u, w);
        }
        for (int i = 1; i <= p; i++) {
            cin >> u >> v >> w;
            g.make_edge(u, v, w);
        }
        g.solveSPFA(s, n);
        for (int i = 1; i <= n; i++) {
            if (g.d[i] >= 0x3f3f3f3f)
                cout << "NO PATH" << endl;
            else
                cout << g.d[i] << endl;
        }
    }
    
  • 相关阅读:
    手机端调用摄像头拍照
    判断浏览器是否支持css3属性或单位
    浏览器页面加载解析渲染机制(一)
    css默认值汇总
    分享几个高效编写JS 的心得
    说几个JS优化技巧吧
    yahoo的30条优化规则
    Jquery的$命名冲突
    C语言时间头文件
    C语言随机数的生成
  • 原文地址:https://www.cnblogs.com/mollnn/p/11615611.html
Copyright © 2020-2023  润新知