dijkstra算法的逆运用

1 背景

        dijkstra算法主要用来求解图的最短单源路径路径问题,且图中不存在负权重环,也不存在负权重的边。

        其实在求解图的最大权重路径的问题上仍然可以使用 Dijkstra 算法,不过需要做一些变化:

        (1)最小堆--->最大堆;

        (2)路径初始化参数以及路径更新的判断条件;

2 题目

2.1 概率最大的路径

1514. 概率最大的路径

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 最长递增路径

剑指 Offer II 112. 最长递增路径

329. 矩阵中的最长递增路径

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值