1514
class Solution {
public:
double maxProbability(int n, vector<vector<int>>& edges, vector<double>& succProb, int start, int end) {
vector<vector<pair<double,int>>> graphs(n);//转化为图
for (int i = 0; i < edges.size(); i++) {//graphs对应下标,存储的是该点所有的儿子(邻居),以及到对应儿子的距离(概率)
auto& e = edges[i];
graphs[e[0]].emplace_back(succProb[i], e[1]);
graphs[e[1]].emplace_back(succProb[i], e[0]);
}
queue<pair<double,int>> Queue;
Queue.push(make_pair(1,start));//存储图的起始位置
vector<double> distTo(n,0);//distTo,存储start到i的距离(权重)
distTo[start] = 1;//基础条件
while(!Queue.empty()){
auto [curProb, curId] = Queue.front();
Queue.pop();
for(auto &[probSon, curSon]:graphs[curId]){//遍历儿子
double distToSon = curProb * probSon; //到son的距离
if(distToSon > distTo[curSon]){//当前路径下雨原来路径
distTo[curSon] = distToSon;//更新
Queue.push(make_pair(distTo[curSon],curSon));
}
}
}
return distTo[end];
}
};
这题就是缝合怪辣,学习很多大佬的优秀代码
本题使用Dijkstra
算法。先介绍该算法是个啥。
Dijkstra算法
,应用于权重为正数的图中。我们给出起始点,终点,该算法可以返回总权重最大/最小的路径或者权重值(如果每一条路的权重都是1,实际上就是返回最短路径,这玩意儿就退化为BFS)Dijkstra算法
,就是BFS++,同时运用贪心的思想。- BFS++:
- 在权重全为1的时候,我们可以将图近似看成多叉树,引入层的概念。每一次遍历我们都往下走一层,最先达到目的地所需要的层数就是最短路径。
- 权重不为1,最先到的不一定是路径最短(引入了权重,虽然经过的节点少,但如果每个节点的权重贼大,哪最终结果也会狠拉,所以不能确定),用层来表示最短路径显然不合适。
- 为了找出最短路径,我们可以按层遍历,找到所有到达目的地的路径,然后选择最短
- 贪心
- 为了保证从start到end的路径最短,我们需要保证从start到其中任意一个节点路径,是可选择路径中最短即可
- eg:从A到Z,有很多条路径。以任意一条路径为例子,假设该路径编号为1,那么A到1中任意一个节点的路径都是可选路径中最短的,比如A,B都是1路径上的,A到B有很多条路径,但是1号路径是从A到B最短的。
- distTo,记录距离信息的数组
- 因为层的方式表示距离不合适,我们需要使用新变量存储关于距离的信息,在这里,我们用distTo数组,存储从start到第i个元素的距离
- BFS++:
本题解法大致框架如下。题目求解的是最大概率,下文成为最大路径
//将edges转化为graphs,对应下标存储的是下标的所有邻居以及对应概率,方便后续处理
for{
//双向图,每个节点互为邻居(儿子)
succProb[i],edges[i][0]->graphs
succProb[i],edges[i][1]->graphs
}
//记录从start到i的距离全部赋值为0,因为求最大路径
distTo(n,0)
//start到start的距离是1,这是base case
distTo[start] = 1
//BSF老传统,状态拓展,每个状态存储的是 1.当前所处节点id,2.start到当前所处节点的路径距离
queue<pair<double,int>> Queue= (1,start)
//状态拓展
while(!Queue.empty()){
curProb,curId = Queue.front()//获取当前要看的节点的信息,curProb:start到当前节点的路径长度,curId:当前节点的Id
Queue.pop()
//拓展状态,获取当前节点的所有儿子
for(probSon,curSon->graphs[curId]){
//找到一条到儿子的路,并计算距离 = 到当前节点的距离*到下一个节点的距离
distToSon = curProb * probSon
//如果新的路径更大,更新,并且拓展状态
if(distToSon > distTo[curSon]){
distTo[curSon] = distToSon;//更新
Queue.push(make_pair(distTo[curSon],curSon));
}
}
}
return distTo[end]
LCP 56
class Solution {
int dir[5] = {-1,0,1,0,-1};//老传统了,配合for(i<4),实现确定4个方向
public:
int conveyorBelt(vector<string>& matrix, vector<int>& start, vector<int>& end) {
int m = matrix.size();
int n = matrix[0].size();
vector<vector<int>> dp(m,vector<int>(n,INT_MAX));//存储到该点施展魔法次数
queue<pair<int,int>> Queue;//队列维护状态,每个状态对应一个坐标
Queue.push(make_pair(start[0],start[1]));
dp[start[0]][start[1]] = 0;//初始状态
while(!Queue.empty()){//状态拓展
auto [R,C] = Queue.front();
Queue.pop();
int _nextR = R, _nextC = C;
getNext(matrix[R][C],_nextR,_nextC);//依据当前节点的字符,获取下一个坐标
for(int i = 0; i < 4; ++i){//选择4个方向移动
int nextR = R + dir[i];
int nextC = C + dir[i+1];
if(isValid(nextR,nextC,m,n)) continue;//非法
if(nextR == _nextR && nextC == _nextC && dp[R][C] < dp[nextR][nextC]) {//移动方向和自身符号表示移动方向一致
dp[nextR][nextC] = dp[R][C];
Queue.push(make_pair(nextR,nextC));
}
else if(dp[R][C] + 1 < dp[nextR][nextC]) {//发现一条到达nextR,nextC所需要更少魔法次数的路
dp[nextR][nextC] = dp[R][C] + 1;
Queue.push(make_pair(nextR,nextC));
}
}
}
return dp[end[0]][end[1]];
}
void getNext(char tar, int& nextR, int& nextC){
switch(tar){
case '^':nextR-=1; break;
case 'v':nextR+=1; break;
case '<':nextC-=1; break;
case '>':nextC+=1; break;
}
}
bool isValid(int nextR, int nextC, int m, int n){
if(nextR < 0 || nextR >= m || nextC < 0 || nextC >= n) return true;
return false;
}
};
思路
在每一个节点,枚举四个方向,排除非法情况。并用dp数组维护到达某一节点所需要的最小魔法次数。