扩点最短路
扩点最短路
不把实际位置看作图上的点,而是把实际位置和该位置的所有状态的组合看作是图上的点,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}); } } } }
本文作者:n1ce2cv
本文链接:https://www.cnblogs.com/sprinining/p/18421991
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [翻译] 为什么 Tracebit 用 C# 开发
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· DeepSeek崛起:程序员“饭碗”被抢,还是职业进化新起点?
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端