首页 > 其他分享 >扩点最短路

扩点最短路

时间:2024-09-20 10:35:28浏览次数:11  
标签:扩点 distance cost int 短路 vector heap include

扩点最短路

不把实际位置看作图上的点,而是把实际位置和该位置的所有状态的组合看作是图上的点,BFS 或者 Dijkstra 的过程不变,只是增加了一些点。

864. 获取所有钥匙的最短路径

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>

using namespace std;

class Solution {
public:
    int rows, columns;
    // 最多 6 把钥匙
    int max_k = 6;
    int key = 0;
    vector<int> move{-1, 0, 1, 0, -1};

    bool isCoordinateLegal(int row, int column) {
        return row >= 0 && row < rows && column >= 0 && column < columns;
    }

    // BFS
    int shortestPathAllKeys(vector<string> &grid) {
        rows = grid.size();
        columns = grid[0].size();

        // (x, y, 持有钥匙的状态)
        queue<vector<int>> q;
        // 找起点
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < columns; ++j) {
                if (grid[i][j] == '@') {
                    q.emplace(vector<int>{i, j, 0});
                } else if (grid[i][j] >= 'a' && grid[i][j] <= 'f') {
                    // 计算获得所有钥匙的最终状态
                    key |= (1 << (grid[i][j] - 'a'));
                }
            }
        }

        // 表示当前位置的某个状态是否从队列中弹出过,状态是指持有钥匙的情况
        vector<vector<vector<bool>>> visited(rows, vector<vector<bool>>(columns));
        for (int i = 0; i < rows; ++i)
            for (int j = 0; j < columns; ++j)
                visited[i][j].resize(key, false);

        int step = 1;
        while (!q.empty()) {
            int size = q.size();
            // 逐层弹出
            for (int i = 0; i < size; ++i) {
                auto f = q.front();
                q.pop();
                int x = f[0];
                int y = f[1];
                // 经过(x, y)后,到达下个点前持有钥匙的状态
                int s = f[2];
                // 四周
                for (int j = 0; j < 4; ++j) {
                    int nx = x + move[j];
                    int ny = y + move[j + 1];
                    // 越界
                    if (!isCoordinateLegal(nx, ny)) continue;
                    char ch = grid[nx][ny];
                    // 墙
                    if (ch == '#') continue;
                    // 锁,且没对应钥匙
                    if (ch >= 'A' && ch <= 'F' && (s & (1 << (ch - 'A'))) == 0) continue;
                    // 钥匙,更新持有的钥匙状态
                    int ns = s;
                    if (ch >= 'a' && ch <= 'f')
                        ns |= (1 << (ch - 'a'));

                    // 获得所有钥匙了
                    if (ns == key) return step;
                    if (visited[nx][ny][ns]) continue;
                    visited[nx][ny][ns] = true;
                    q.emplace(vector<int>{nx, ny, ns});
                }
            }
            step++;
        }

        return -1;
    }
};

LCP 35. 电动车游城市

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>

using namespace std;

class Solution {
public:
    struct cmp {
        bool operator()(vector<int> &v1, vector<int> &v2) {
            return v1[2] > v2[2];
        }
    };

    int electricCarPlan(vector<vector<int>> &paths, int cnt, int start, int end, vector<int> &charge) {
        int n = charge.size();
        vector<vector<pair<int, int>>> graph(n);
        // 无向图
        for (const auto &item: paths) {
            graph[item[0]].emplace_back(make_pair(item[1], item[2]));
            graph[item[1]].emplace_back(make_pair(item[0], item[2]));
        }

        // (点, 到这个点的剩余电量, 代价)
        priority_queue<vector<int>, vector<vector<int>>, cmp> heap;
        // vector[i][j] 为到达 i 点时剩余 j 电量的最小代价
        vector<vector<int>> distance(n, vector<int>(cnt + 1, INT_MAX));
        // 访问标记
        vector<vector<bool>> visited(n, vector<bool>(cnt + 1, false));

        heap.emplace(vector<int>{start, 0, 0});
        distance[start][0] = 0;

        while (!heap.empty()) {
            auto top = heap.top();
            heap.pop();
            int position = top[0];
            int power = top[1];
            int cost = top[2];
            // 结束
            if (position == end) return cost;
            if (visited[position][power]) continue;
            visited[position][power] = true;
            // 充一格电,到图中扩出来的点,也就是这个点的其他状态
            if (power < cnt
                && !visited[position][power + 1]
                && (cost + charge[position] < distance[position][power + 1])) {
                distance[position][power + 1] = cost + charge[position];
                heap.emplace(vector<int>{position, power + 1, distance[position][power + 1]});
            }
            // 不充电,直接去别的点
            for (const auto &item: graph[position]) {
                int nextPosition = item.first;
                int restPower = power - item.second;
                int nextCost = cost + item.second;
                // 到不了下个点,或者下个状态已经弹出过,就跳过
                if (restPower < 0 || visited[nextPosition][restPower]) continue;
                if (nextCost < distance[nextPosition][restPower]) {
                    distance[nextPosition][restPower] = nextCost;
                    heap.emplace(vector<int>{nextPosition, restPower, nextCost});
                }
            }
        }

        return -1;
    }
};

P4568 [JLOI2011] 飞行路线

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>

using namespace std;

int n, m, k, s, t;

vector<int> head;
vector<int> nxt;
vector<int> to;
vector<int> weight;
int cnt;

void build() {
    head.resize(n, 0);
    fill(head.begin(), head.end(), 0);
    nxt.resize((m << 1) + 1);
    to.resize((m << 1) + 1);
    weight.resize((m << 1) + 1);
    cnt = 1;
}

void addEdge(int u, int v, int w) {
    nxt[cnt] = head[u];
    to[cnt] = v;
    weight[cnt] = w;
    head[u] = cnt;
    cnt++;
}

struct cmp {
    bool operator()(vector<int> &v1, vector<int> &v2) {
        return v1[2] > v2[2];
    }
};

int main() {
    cin >> n >> m >> k >> s >> t;
    build();
    for (int i = 0, u, v, w; i < m; ++i) {
        cin >> u >> v >> w;
        addEdge(u, v, w);
        addEdge(v, u, w);
    }

    // distance[i][j] 为到达 i 点,剩余免费乘坐次数 j 次的最少代价
    vector<vector<int>> distance(n, vector<int>(k + 1, 0x7fffffff));
    // 访问标记
    vector<vector<bool>> visited(n, vector<bool>(k + 1, false));
    // (点,到点后剩余的免费次数,最少代价)
    priority_queue<vector<int>, vector<vector<int>>, cmp> heap;

    distance[s][k] = 0;
    heap.emplace(vector<int>{s, k, 0});

    while (!heap.empty()) {
        auto top = heap.top();
        heap.pop();
        int u = top[0];
        int free = top[1];
        int cost = top[2];
        // 结束
        if (u == t) {
            cout << cost;
            return 0;
        }
        if (visited[u][free]) continue;
        visited[u][free] = true;

        for (int ei = head[u]; ei > 0; ei = nxt[ei]) {
            int v = to[ei];
            int w = weight[ei];
            // 使用一张票
            if (free > 0
                && !visited[v][free - 1]
                && cost < distance[v][free - 1]) {
                distance[v][free - 1] = cost;
                heap.emplace(vector<int>{v, free - 1, cost});
            }
            // 不使用
            if (!visited[v][free]
                && cost + w < distance[v][free]) {
                distance[v][free] = cost + w;
                heap.emplace(vector<int>{v, free, cost + w});
            }
        }
    }
}

标签:扩点,distance,cost,int,短路,vector,heap,include
From: https://www.cnblogs.com/sprinining/p/18421991

相关文章

  • 【MATLAB源码-第227期】基于matlab的北方苍鹰优化算法(NGO)机器人栅格路径规划,输出做
    操作环境:MATLAB2022a1、算法描述鼠群优化算法(RatSwarmOptimization,RSO)简介鼠群优化算法(RatSwarmOptimization,RSO)是一种模仿鼠类群体觅食行为的优化算法。该算法属于群体智能算法,通过模拟鼠群在复杂环境中寻找食物的行为,来解决各种优化问题。鼠类在觅食过程中表现......
  • 图论篇--代码随想录算法训练营第五十九天打卡|Bellman_ford 算法精讲,SPFA算法,Bellman
    本系列算法用来解决有负权边的情况Bellman_ford算法精讲题目链接:94.城市间货物运输I题目描述:某国为促进城市间经济交流,决定对货物运输提供补贴。共有n个编号为1到n的城市,通过道路网络连接,网络中的道路仅允许从某个城市单向通行到另一个城市,不能反向通行。网络......
  • 最短路之 $dijekstra$ 学习笔记
    最短路之\(dijekstra\)学习笔记复习\(dijekstra!\)怎么说,就写一下\(dij\)的实现过程吧\(dij\)的思路就是,将结点分成两个集合:已确定最短路长度的点集(记为$S$集合)的和未确定最短路长度的点集(记为$T$集合)。一开始所有的点都属于$T$集合。初始化$dis(s)=0$,其......
  • 最短路 || 最长路 || 次短路
    大致目录最短路单源最短路径1.Bellman-Ford算法2.SPFA算法3.Dijkstra算法多源最短路径Floyd算法总结最长路SPFA拓扑排序非严格次短路严格次短路因为之前一直好久之前用的博客园,现在上大学了慢慢开始用CSDN,把之前写的一些年轻的文章先拿过来用用,嘻嘻。如题,这......
  • Dijkstra求最短路
    Dijkstra求最短路849.Dijkstra求最短路I给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为正值。请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出−1。输入格式第一行包含整数n和m。接下来m行每行包含三个整数x,y,z,表示存......
  • 【图论】Johnson全源最短路算法
    ·2024-9-11·最后更新时间2024-9-11作者学会了一个叫做\(Johnson\)的算法,所以就有了这篇博客......Johnson算法是一个高效处理全源最短路的算法其实也很慢,但目前是最高效的为了更加方便你们接下来的学习我希望你们已经掌握了基本的最短路算法(SPFA,Dijsktra,Bellman-Ford,Floyd......
  • 图与网络——最短路问题精解
    最短路问题(ShortestPathProblem)是图论中的一个经典问题,广泛应用于现实世界中的多个领域。该问题的核心在于如何在一个图中找到给定起点和终点之间路径权重最小的路径。路径权重通常代表时间、成本、距离等因素,因此最短路问题不仅具有理论上的研究价值,还在实际问题的解决中发挥了......
  • 【算法笔记】多源最短路问题——Floyd算法
    0.前言在图中,如果要求任意两点间的距离,则可以使用Floyd(\(\mathcalO(N^3)\)......
  • 【算法笔记】单源最短路问题——Dijkstra算法(无优化/优先队列/set优化)
    0.前言Dijkstra算法可在\(\mathcalO(m\logm)\)或\(\mathcalO(m\logn)\)的时间内求解无负权单源最短路问题。本文中,我们将详细介绍算法的原理、实现,以及常用的两种优化。另外,Dijkstra算法也不要乱用,比如说多源的最短路,用Dijkstra求解的复杂度只有\(\mathcalO(nm\logm)\),但......
  • 信息学奥赛初赛天天练-86-NOIP2014普及组-基础题5-球盒问题、枚举算法、单源最短路、D
    1NOIP2014普及组基础题521把M个同样的球放到N个同样的袋子里,允许有的袋子空着不放,问共有多少种不同的放置方法?(用K表示)()例如,M=7,N=3时,K=8;在这里认为(5,1,1)和(1,5,1)是同一种放置方法。问:M=8,N=5时,K=()22如图所示,图中每条边上的数字表示该边的长度,则从......