1 背景
dijkstra算法主要用来求解图的最短单源路径路径问题,且图中不存在负权重环,也不存在负权重的边。
其实在求解图的最大权重路径的问题上仍然可以使用 Dijkstra 算法,不过需要做一些变化:
(1)最小堆--->最大堆;
(2)路径初始化参数以及路径更新的判断条件;
2 题目
2.1 概率最大的路径
class Solution {
public:
double maxProbability(int n, vector<vector<int>>& edges, vector<double>& succProb, int start, int end) {
vector<vector<pair<int, double>>> graph;
buildGraph(n, edges, succProb, graph);
return dijkstra(n, start, end, graph);
}
void buildGraph(int n, vector<vector<int>>& edges, vector<double>& succProb, vector<vector<pair<int, double>>>& graph)
{
graph.resize(n);
for (int i = 0; i < edges.size(); ++i)
{
int from = edges[i][0], to = edges[i][1];
graph[from].push_back(make_pair(to, succProb[i]));
graph[to].push_back(make_pair(from, succProb[i]));
}
}
// dijkstra 算法的逆运用
double dijkstra(int n, int start, int end, vector<vector<pair<int, double>>>& graph)
{
// 定义:distTo[i] 的值就是起点 start 到达节点 i 的最大,所以初始化值使用INT_MIN
vector<double> distTo(n, INT_MIN);
// base case,start 到 start 的最小概率设置为1
distTo[start] = 1;
// 优先级队列,distFromStart 较大的排在前面
struct cmp
{
//[0]: 当前节点, [1]: 从start到达当前节点的最大概率,更换成最大堆
bool operator () (const pair<int, double>& a, const pair<int, double>& b)
{
// return a.second > b.second; //最小堆
return a.second < b.second; //最大堆
}
};
//构建基于权重的最大堆
priority_queue<pair<int, double>, vector<pair<int, double>>, cmp> maxHeap;
// 从起点 start 开始进行 BFS
maxHeap.push(make_pair(start, 1));
while (!maxHeap.empty())
{
auto currNode = maxHeap.top();
maxHeap.pop();
int curNodeID = currNode.first;
if (curNodeID == end)
return distTo[curNodeID];
// 将 curNode 的相邻节点装入队列
for (auto& neighbor : graph[curNodeID])
{
int nextNodeID = neighbor.first;
// int distToNextNode = distTo[curNodeID] + neighbor.second;
double distToNextNode = distTo[curNodeID] * neighbor.second;
// if (distTo[nextNodeID] > distToNextNode)//最短路径的判断条件
if (distTo[nextNodeID] < distToNextNode)//最长路径的判断条件,此处也就是最大概率路径
{
distTo[nextNodeID] = distToNextNode;
maxHeap.push(make_pair(nextNodeID, distToNextNode));
}
}
}
return (int)distTo[end] == INT_MIN ? 0.0 : distTo[end];
}
};
2.2 最长递增路径
class Solution {
public:
int longestIncreasingPath(vector<vector<int>>& matrix) {
// 方法一:使用DFS超出时间限制
// int n = matrix.size(), m = matrix[0].size();
// vector<vector<bool>> visited(n, vector<bool>(m, false));
// int maxLength = 0;
// for (int i=0;i<n;++i)
// {
// for (int j=0;j<m;++j)
// {
// maxLength = std::max(maxLength, dfs(matrix, i, j, 1, visited));
// }
// }
// return maxLength;
//方法二:抽象成图,一个元素只能与大于该元素的方向上的那个元素形成权重为1的连通,构造完这个图之后使用 dijsktra 算法即可
//不过这里是对 dijkstra 的逆运用,也就是使用 dijkstra 进行最大值路径的求解。不过这里求解的是该图中最大值路径的一个点对点的对。
//而 dijkstra 求解的是单个起点到图中其他所有节点的最长路径(这里是对 dijkstra 逆运用,也就是求解的最长路径),所以此处需要遍历
//图中的任何一个节点,使它们都作为起点执行一遍 Dijkstra 算法,但是这样效率不高(实际验证是总时间超时),可以采用《算法导论3rd-p399》
//中第25章的内容:“所有结点对的最短路径问题”,同样将“最短”路径的求解问题转换成“最长”路径的求解问题。
vector<vector<pair<int,int>>> graph;
buildGraph(matrix, graph);
int n = matrix.size(), m = matrix[0].size(), maxPathLength = 0, from = 0;
vector<int> r;
for (int i=0;i<n;++i)
{
for (int j=0;j<m;++j)
{
from = m * i + j;
r = dijkstra(from, graph);
for (auto& item : r)
{
if (item == INT_MAX)
continue;
maxPathLength = std::max(maxPathLength, item);
}
}
}
return maxPathLength + 1;
}
//方法一
int dfs(vector<vector<int>>& matrix, int r, int c, int count, vector<vector<bool>>& visited)
{
if (visited[r][c])
return count;
visited[r][c] = true;
int maxLength = count;
vector<pair<int,int>> neighbours{{-1,0},{1,0},{0,-1},{0,1}};
int n = matrix.size(), m = matrix[0].size();
for (auto& item : neighbours)
{
int x = r + item.first, y = c + item.second;
if (x < 0 || x >= n || y < 0 || y >= m || matrix[x][y] <= matrix[r][c])
continue;
maxLength = std::max(maxLength, dfs(matrix, x, y, count+1, visited));
}
visited[r][c] = false;
return maxLength;
}
// 方法二
void buildGraph(vector<vector<int>>& matrix, vector<vector<pair<int,int>>>& graph)
{
int n = matrix.size(), m = matrix[0].size(), from = 0, to = 0;
vector<pair<int,int>> neighbours{{-1,0},{1,0},{0,-1},{0,1}};
if (n * m == 0)
{
graph.resize(n + m);
}
else
{
graph.resize(n * m);
}
for (int i=0;i<n;++i)
{
for (int j=0;j<m;++j)
{
from = m * i + j;
for (auto& item : neighbours)
{
int x = i + item.first, y = j + item.second;
if (x < 0 || x >= n || y < 0 || y >= m || matrix[x][y] <= matrix[i][j])
continue;
to = m * x + y;
graph[from].push_back({to, 1});
}
}
}
}
//graph是图的邻接边实现,第一维是起点,二维是<终点、开销>
//dijkstra的逆运用
vector<int> dijkstra(int start, vector<vector<pair<int,int>>>& graph)
{
// 定义:distTo[i] 的值就是起点 start 到达节点 i 的“最长”路径权重,所以初始化值设置为INT_MIN
vector<int> distTo(graph.size(), INT_MIN);
// base case,start 到 start 的最短距离就是 0
distTo[start] = 0;
// 优先级队列,distFromStart 较大的排在前面
struct cmp
{
//[0]: 当前节点, [1]: 从start到达当前节点的“最大”路径权重(本题目使用最大堆)
bool operator () (const pair<int,int>& a, const pair<int,int>& b)
{
// return a.second > b.second;//最小堆
return a.second < b.second;//最大堆
}
};
//构建基于权重的最大堆
priority_queue<pair<int,int>, vector<pair<int,int>>, cmp> maxHeap;
// 从起点 start 开始进行 BFS
maxHeap.push(make_pair(start, -1));
while (!maxHeap.empty())
{
auto currNode = maxHeap.top();
maxHeap.pop();
int curNodeID = currNode.first;
// 将 curNode 的相邻节点装入队列
for (auto& neighbor : graph[curNodeID])
{
int nextNodeID = neighbor.first;
int distToNextNode = distTo[curNodeID] + neighbor.second;
// if (distTo[nextNodeID] > distToNextNode) //最短路径的判断条件
if (distTo[nextNodeID] < distToNextNode) //最长路径的判断条件,此处也就是最大概率路径
{
distTo[nextNodeID] = distToNextNode;
maxHeap.push(make_pair(nextNodeID, distToNextNode));
}
}
}
return distTo;
}
};
2.3
3
4