-
https://leetcode.cn/problems/minimum-cost-of-a-path-with-special-roads/?
-
给你一个数组 start ,其中 start = [startX, startY] 表示你的初始位置位于二维空间上的 (startX, startY) 。另给你一个数组 target ,其中 target = [targetX, targetY] 表示你的目标位置 (targetX, targetY) 。
-
从位置 (x1, y1) 到空间中任一其他位置 (x2, y2) 的代价是 |x2 - x1| + |y2 - y1| 。
-
给你一个二维数组 specialRoads ,表示空间中存在的一些特殊路径。其中
specialRoads[i] = [x1i, y1i, x2i, y2i, costi] 表示第 i 条特殊路径可以从 (x1i, y1i) 到 (x2i, y2i) ,但成本等于 costi
。你可以使用每条特殊路径任意次数。 -
返回从 (startX, startY) 到 (targetX, targetY) 所需的最小代价。
示例 1:
输入:start = [1,1], target = [4,5], specialRoads = [[1,2,3,3,2],[3,4,4,5,1]]
输出:5
解释:从 (1,1) 到 (4,5) 的最优路径如下:
- (1,1) -> (1,2) ,移动的代价是 |1 - 1| + |2 - 1| = 1 。
- (1,2) -> (3,3) ,移动使用第一条特殊路径,代价是 2 。
- (3,3) -> (3,4) ,移动的代价是 |3 - 3| + |4 - 3| = 1.
- (3,4) -> (4,5) ,移动使用第二条特殊路径,代价是 1 。
总代价是 1 + 2 + 1 + 1 = 5 。
可以证明无法以小于 5 的代价完成从 (1,1) 到 (4,5) 。
示例 2:
输入:start = [3,2], target = [5,7], specialRoads = [[3,2,3,4,4],[3,3,5,5,5],[3,4,5,6,6]]
输出:7
解释:最优路径是不使用任何特殊路径,直接以 |5 - 3| + |7 - 2| = 7 的代价从初始位置到达目标位置。
- Dijkstra
- 类似广度优先搜索的方法解决赋权图的单源最短路径问题。(本算法每次取出未访问结点中距离最小的,用该结点更新其他结点的距离。)
- Dijkstra 一个顶点作为源结点然后找到该顶点到图中所有其它结点的最短路径,产生一个最短路径树。
- 注意:Dijkstra 算法不能有效处理带有负权边的图.
因为是完全图的题目,所以可以省略建图的过程
class Solution {
private:
int getCost(int x1, int y1, int x2, int y2) {
return abs(x2 - x1) + abs(y2 - y1);
}
public:
int minimumCost(vector<int>& s, vector<int>& t, vector<vector<int>>& sr) {
sr.insert(sr.begin(), {s[0], s[1], s[0], s[1], 0});
sr.push_back({t[0], t[1], t[0], t[1], 0});
// Dijkstra
const int INF = INT32_MAX;
int n = sr.size();
vector<int> dist(n, INF);// record min dist {sr[0][0], sr[0][1]} to {sr[*][2], sr[*][3]}
vector<bool> vis(n, false);
dist[0] = 0;
for (int i = 0; i < n; i++) {
int minDist = INF;
int u = -1;
for (int j = 0; j < n; j++) {//每次取出未访问结点中距离最小的:u
if (!vis[j] && dist[j] < minDist) {
minDist = dist[j];
u = j;
}
}
if (u == -1) break;
vis[u] = true;//用该结点更新其他结点的距离
for (int v = 0; v < n; v++) {//接着我们看与u连接的点
if (u == v) continue;
int toStartOfv = getCost(sr[u][2], sr[u][3], sr[v][0], sr[v][1]);
int alt = dist[u] + toStartOfv + min(sr[v][4], getCost(sr[v][0], sr[v][1], sr[v][2], sr[v][3]));
dist[v] = min(dist[v], alt);
}
}
return dist[n-1];
}
};
cg
- 有dfs的版本https://zhuanlan.zhihu.com/p/554749044
#include <iostream>
using namespace std;
//从城市1到城市5最短路径为多少?
int mp[105][105];//图
int vis[105];//测试数组
int x, y, r;
int n; int m;
int minx = 1000000;
void dfs(int step, int sum) {
if (sum > minx) {
return;
}
if (step == n) {//当扫描到最后一个城市时
if(sum<minx){
minx = sum;//更新
return;
}
}
for (int i = 1; i <=n; i++) {
if (mp[step][i] != 0 &&vis[i]==0) {//该点没有被标记,且该点存在连接
vis[i] = 1;
dfs(i, sum + mp[step][i]);
vis[i] = 0;
}
}
}
int main()
{
cin >> n>>m;
while (m--) {
cin >> x >> y >> r;
mp[x][y] = r;//该图为有向图,是由x到y的距离
}
dfs(1, 0);
cout << minx << endl;
}
- Floyed
void floyed(){
for (int k = 1; k <= n; k++) {//从1到n依次各点进行中转
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (e[i][j] > e[i][k] + e[k][j]) {//如果该路径更短,更新成该路径
e[i][j] = max(e[i][j],e[i][k] + e[k][j]);
}
}
}
}
}
CG
最短路径问题是指在一个加权有向图中,找到从起点到终点的最短路径。常见的最短路径算法有:
-
Dijkstra算法:适用于边权非负的图,每次选择距离起点最近的一个顶点进行扩展。
-
Bellman-Ford算法:适用于边权可以为负的图,通过对所有边进行松弛操作,不断更新每个顶点的最短路径。
-
Floyd算法:适用于任意图,通过动态规划的思想,计算出所有顶点之间的最短路径。
-
A*算法:适用于带有启发式函数的图,通过估计从当前节点到目标节点的距离,选择距离目标节点最近的节点进行扩展。
以上算法都可以求解最短路径,具体选择哪个算法要根据具体问题的特点和需求进行选择。
Dijkstra算法是一种用于求解加权有向图中单源最短路径的算法,它采用贪心策略,每次选择距离起点最近的一个顶点进行扩展,直到到达终点或者所有可达顶点都被扩展完毕。
具体实现过程如下:
-
初始化:将起点到自身的距离设为0,其他点的距离设为无穷大。
-
选择距离起点最近的未标记顶点,标记该顶点,并更新该顶点的邻居节点的距离值。具体步骤如下:
a. 对于当前选中的顶点v,遍历其所有邻居节点w,计算起点到w的距离dist[v]+weight(v,w),其中dist[v]表示起点到v的最短距离,weight(v,w)表示vDijkstra算法是一种用于求解加权有向图中单源最短路径的算法,它采用贪心策略,每次选择距离起点最近的一个顶点进行扩展,直到到达终点或者所有可达顶点都被扩展完毕。
具体实现过程如下:
-
初始化:将起点到自身的距离设为0,其他点的距离设为无穷大。
-
选择距离起点最近的未标记顶点,标记该顶点,并更新该顶点的邻居节点的距离值。具体步骤如下:
a. 对于当前选中的顶点v,遍历其所有邻居节点w,计算起点到w的距离dist[v]+weight(v,w),其中dist[v]表示起点到v的最短距离,weight(v,w)表示v到w的边权。
b. 如果dist[v]+weight(v,w)小于dist[w],则更新dist[w]的值为dist[v]+weight(v,w)。
-
重复步骤2,直到终点被标记或者所有可达顶点都被标记。
-
根据dist数组得到起点到终点的最短路径。
Dijkstra算法的时间复杂度O(V^2)
,其中V为顶点数,但是可以通过使用优先队列来优化算法,使时间复杂度降为O(ElogV),其中E为边数。