算法加训之最短路 上(dijkstra算法)
目录
P4779 【模板】单源最短路径(标准版)(洛谷)
思路
743. 网络延迟时间(力扣)
思路
1514.概率最大路径(力扣)
思路
1631.最小体力消耗路径
思路
1976. 到达目的地的方案数
思路
P1144 最短路计数(洛谷)
思路
P1462 通往奥格瑞玛的道路
思路
2642. 设计可以求最短路径的图类
思路
778. 水位上升的泳池中游泳
思路
787. K 站中转内最便宜的航班
思路
dijkstra算法的运用
先说我对dijkstra的理解吧,然后看完这些东西,再写题,我的第一道题是模版题,可以配合看一下
1,dijkstra的构成,首先是图,链式前向星(邻接表,邻接矩阵)这仨都行哈,节点数量大的话就用链式前向星,邻接表比较方便(我不太用邻接矩阵的),其次是小根堆,他用来保证我们每次找到的节点都离源节点最近的节点。然后是distance_数组用来记录源节点到每个节点的最短距离,初始化为一个很大的值就好(我都设为INT_MAX),没了就这几个。
2,代码,就先建图嘛,然后对上面说的这些结构该初始化的初始化,,小根堆里面先push一下代价0和源节点,因为自己到自己代价为0,distance_数组进行初始化为INT_MAX,接下来就是核心代码,核心代码的解析在下面模版题上有详细注释
P4779 【模板】单源最短路径(标准版)(洛谷)
题目背景
2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路。
然后呢?
100→60;
Ag→Cu;
最终,他因此没能与理想的大学达成契约。
小 F 衷心祝愿大家不再重蹈覆辙。
题目描述
给定一个 n 个点,m 条有向边的带非负权图,请你计算从 s 出发,到每个点的距离。
数据保证你能从 s 出发到任意点。
输入格式
第一行为三个正整数 n,m,s。 第二行起 m 行,每行三个非负整数 ui,vi,wi,表示从 ui 到 vi 有一条权值为 wi 的有向边。
输出格式
输出一行 n 个空格分隔的非负整数,表示 s 到每个点的距离。
输入输出样例
输入 #1复制
4 6 1 1 2 2 2 3 2 2 4 1 1 3 5 3 4 3 1 4 4输出 #1复制
0 2 4 3说明/提示
样例解释请参考 数据随机的模板题。
1≤n≤105;
1≤m≤2×105;
s=1;
1≤ui,vi≤n;
0≤wi≤109,
0≤∑wi≤109。
本题数据可能会持续更新,但不会重测,望周知。
思路
这题就是个模版提,思路就是上面讲算法解析,配合着看理解就行,因为这题数据给的是1e5我就用链式前向星了
#include<bits/stdc++.h>
using namespace std;
int n,m,s;
const int N=1e5+10;
struct edge{int to;int w;int next;
}graph[N*2];
int cnt,head[N];
void add_edge(int u,int v,int w){cnt++;graph[cnt].to=v;graph[cnt].w=w;graph[cnt].next=head[u];head[u]=cnt;
}
int main(){cin>>n>>m>>s;for(int i=0;i<m;i++){int u,v,w;cin>>u>>v>>w;add_edge(u,v,w); }vector<int>distance_(N,INT_MAX);distance_[s]=0;//算出s到每个点的最短距离 priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> pq;pq.push({0,s});while(!pq.empty()){//先取出来源节点到达当前节点的代价dist,和当前是哪个节点u int dist=pq.top().first;int u=pq.top().second;//记得弹出去,要不然就进行不下去 pq.pop();//如果到达当前节点的代价比你存的到达当前节点的最小代价大,就continue,这个点就不走了 if(dist>distance_[u]) continue;//开始遍历图,也就是遍历u,看看u连接的节点把他们扔进堆里面继续进行操作 for(int i=head[u];i;i=graph[i].next){int to=graph[i].to;int w=graph[i].w;//如果之前存的到达to的距离比现在发现的代价大就 更新 if(distance_[to]>dist+w){distance_[to]=dist+w;pq.push({distance_[to],to});}}} for(int i=1;i<=n;i++){cout<<distance_[i]<<' ';}}
743. 网络延迟时间(力扣)
743. 网络延迟时间 - 力扣(LeetCode)https://leetcode.cn/problems/network-delay-time/description/
有
n
个网络节点,标记为1
到n
。给你一个列表
times
,表示信号经过 有向 边的传递时间。times[i] = (ui, vi, wi)
,其中ui
是源节点,vi
是目标节点,wi
是一个信号从源节点传递到目标节点的时间。现在,从某个节点
K
发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回-1
。示例 1:
输入:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2 输出:2示例 2:
输入:times = [[1,2,1]], n = 2, k = 1 输出:1示例 3:
输入:times = [[1,2,1]], n = 2, k = 2 输出:-1提示:
1 <= k <= n <= 100
1 <= times.length <= 6000
times[i].length == 3
1 <= ui, vi <= n
ui != vi
0 <= wi <= 100
所有
(ui, vi)
对都 互不相同(即,不含重复边)
思路
其实和上面那个几乎一样,这个就是让你算一下从k节点开始遍历完,所消耗的全部代价,那我们只需要在distance里找出最大值就好,因为distance里存的是源节点到所有节点的最近距离,所以里面当然有源节点所到达的最后一个节点,这个节点李村的就是从源节点走完所有节点的代价
class Solution {
public:int networkDelayTime(vector<vector<int>>& times, int n, int k) {//先建图vector<vector<pair<int,int>>> graph(n+1);for(auto &edge:times){graph[edge[0]].emplace_back(edge[1],edge[2]);}//distance,visited数组vector<int>distance(n+1,INT_MAX);vector<bool>visited(n+1);//再建个小根堆priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> hp;hp.emplace(0,k);//k节点到自己距离为0;distance[k]=0;while(!hp.empty()){auto [dist,u]=hp.top();hp.pop();if(visited[u])continue;visited[u]=true;for(auto& [v,w]:graph[u]){if(!visited[v]&&distance[u]+w<distance[v]){distance[v]=w+distance[u];hp.emplace(distance[v],v);}}}//走完也就是把每个节点都弹出过了,也就脱离循环了int max1=*max_element(distance.begin()+1,distance.end());return max1==INT_MAX?-1:max1;}
};
1514.概率最大路径(力扣)
1514. 概率最大的路径 - 力扣(LeetCode)https://leetcode.cn/problems/path-with-maximum-probability/
有
n
个网络节点,标记为1
到n
。给你一个列表
times
,表示信号经过 有向 边的传递时间。times[i] = (ui, vi, wi)
,其中ui
是源节点,vi
是目标节点,wi
是一个信号从源节点传递到目标节点的时间。现在,从某个节点
K
发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回-1
。示例 1:
输入:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2 输出:2示例 2:
输入:times = [[1,2,1]], n = 2, k = 1 输出:1示例 3:
输入:times = [[1,2,1]], n = 2, k = 2 输出:-1提示:
1 <= k <= n <= 100
1 <= times.length <= 6000
times[i].length == 3
1 <= ui, vi <= n
ui != vi
0 <= wi <= 100
- 所有
(ui, vi)
对都 互不相同(即,不含重复边)
思路
这个就是小根堆换成大根堆,这样就能求出最大概率,然后因为是概率存的时候换成double
别的都跟上面一样
class Solution {
public:double maxProbability(int n, vector<vector<int>>& edges, vector<double>& succProb, int start_node, int end_node) {vector<vector<pair<int,double>>>graph(n);vector<double>distance_(n,0);for (int i = 0; i < edges.size(); i++) {auto& e = edges[i];graph[e[0]].emplace_back(e[1],succProb[i]);graph[e[1]].emplace_back(e[0],succProb[i]);}priority_queue<pair<double,int>>pq;pq.push({1,start_node});//自己到自己的概率为1distance_[start_node]=1;while(!pq.empty()){auto [dist,u]=pq.top();pq.pop();if(dist<distance_[u]) continue;for(auto &[to,w]:graph[u]){if(distance_[to]<w*dist){distance_[to]=w*dist;pq.push({distance_[to],to});}}}return distance_[end_node];}
};
1631.最小体力消耗路径
1514. 概率最大的路径 - 力扣(LeetCode)https://leetcode.cn/problems/path-with-maximum-probability/
你准备参加一场远足活动。给你一个二维
rows x columns
的地图heights
,其中heights[row][col]
表示格子(row, col)
的高度。一开始你在最左上角的格子(0, 0)
,且你希望去最右下角的格子(rows-1, columns-1)
(注意下标从 0 开始编号)。你每次可以往 上,下,左,右 四个方向之一移动,你想要找到耗费 体力 最小的一条路径。一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。
请你返回从左上角走到右下角的最小 体力消耗值 。
示例 1:
输入:heights = [[1,2,2],[3,8,2],[5,3,5]] 输出:2 解释:路径 [1,3,5,3,5] 连续格子的差值绝对值最大为 2 。 这条路径比路径 [1,2,2,2,5] 更优,因为另一条路径差值最大值为 3 。示例 2:
输入:heights = [[1,2,3],[3,8,4],[5,3,5]] 输出:1 解释:路径 [1,2,3,4,5] 的相邻格子差值绝对值最大为 1 ,比路径 [1,3,5,3,5] 更优。示例 3:
输入:heights = [[1,2,1,1,1],[1,2,1,2,1],[1,2,1,2,1],[1,2,1,2,1],[1,1,1,2,1]] 输出:0 解释:上图所示路径不需要消耗任何体力。提示:
rows == heights.length
columns == heights[i].length
1 <= rows, columns <= 100
1 <= heights[i][j] <= 106
思路
看题上要求的是啥,他说的最小体力消耗就是,两个相邻格子之间的差值,那我们只要把这个差值作为代价存进小根堆里面就可以用dijkstra算法进行求解了,这里我们还要自己给小根堆构建一个排序,利用结构体,其他的看代码就能理解了
if(c>distance_[a][b]) continue;这里其实我们可以用个visited数组代替,上面的题一样,因为我们利用堆每次走的都是最有效的路,鄋走过的就不用走了
class Solution {
public:struct Node{int x,y,cost;Node(int x_,int y_,int cost_) : x(x_),y(y_),cost(cost_){}bool operator>(const Node& other) const{return cost>other.cost;}};int mv[5]={-1,0,1,0,-1};int minimumEffortPath(vector<vector<int>>& heights) {int m=heights.size();int n=heights[0].size();//构建小根堆priority_queue<Node,vector<Node>,greater<Node>>pq;pq.push({0,0,0});//自己到自己的差值是0vector<vector<int>>distance_(m+1,vector<int>(n+1,INT_MAX));distance_[0][0]=0;while(!pq.empty()){auto[a,b,c]=pq.top();pq.pop();if(a==m-1&&b==n-1) return c;if(c>distance_[a][b]) continue;for(int i=0,nx,ny;i<4;i++){nx=a+mv[i];ny=b+mv[i+1];if(nx>=0&&ny>=0&&nx<m&&ny<n){int nc=max(c,abs(heights[nx][ny]-heights[a][b]));if(nc<distance_[nx][ny]){distance_[nx][ny]=nc;pq.push({nx,ny,nc});}}}}return -1;}
};
1976. 到达目的地的方案数
1976. 到达目的地的方案数 - 力扣(LeetCode)https://leetcode.cn/problems/number-of-ways-to-arrive-at-destination/description/
你在一个城市里,城市由
n
个路口组成,路口编号为0
到n - 1
,某些路口之间有 双向 道路。输入保证你可以从任意路口出发到达其他任意路口,且任意两个路口之间最多有一条路。给你一个整数
n
和二维整数数组roads
,其中roads[i] = [ui, vi, timei]
表示在路口ui
和vi
之间有一条需要花费timei
时间才能通过的道路。你想知道花费 最少时间 从路口0
出发到达路口n - 1
的方案数。请返回花费 最少时间 到达目的地的 路径数目 。由于答案可能很大,将结果对
109 + 7
取余 后返回。示例 1:
输入:n = 7, roads = [[0,6,7],[0,1,2],[1,2,3],[1,3,3],[6,3,3],[3,5,1],[6,5,1],[2,5,1],[0,4,5],[4,6,2]] 输出:4 解释:从路口 0 出发到路口 6 花费的最少时间是 7 分钟。 四条花费 7 分钟的路径分别为: - 0 ➝ 6 - 0 ➝ 4 ➝ 6 - 0 ➝ 1 ➝ 2 ➝ 5 ➝ 6 - 0 ➝ 1 ➝ 3 ➝ 5 ➝ 6示例 2:
输入:n = 2, roads = [[1,0,10]] 输出:1 解释:只有一条从路口 0 到路口 1 的路,花费 10 分钟。提示:
1 <= n <= 200
n - 1 <= roads.length <= n * (n - 1) / 2
roads[i].length == 3
0 <= ui, vi <= n - 1
1 <= timei <= 109
ui != vi
- 任意两个路口之间至多有一条路。
- 从任意路口出发,你能够到达其他任意路口。
思路
这个就是增加一个cnt数组来记录源节点到每个节点最短路的路径数,其他的都一样
还有就是这个数要用long long 最开始我就是没弄这个一直过不完,后来把所有int都换了
更新规则:
发现更短路径:当找到一条比当前记录更短的路径时,需要重置 cnt[i]
。
路径长度相同:当遇到另一条路径长度与当前记录相同时,需要累加 cnt[i]
。
class Solution {
public: int countPaths(int n, vector<vector<int>>& roads) {vector<vector<pair<long long,long long>>> graph(n);for(auto &edge:roads){graph[edge[0]].push_back({edge[1],edge[2]});graph[edge[1]].push_back({edge[0],edge[2]});}vector<long long>distance_(n,LLONG_MAX);priority_queue<pair<long long,long long>,vector<pair<long long,long long>>,greater<pair<long long,long long>>>pq;pq.push({0,0});distance_[0]=0;vector<int>cnt(n,0);//记录从起点到每个节点的最短路的个数cnt[0]=1;while(!pq.empty()){auto [w,u]=pq.top();pq.pop();if(w>distance_[u]) continue;for(auto [v,dist]:graph[u]){if(dist+w<distance_[v]){distance_[v]=dist+w;cnt[v]=cnt[u];//如果有更短得多路就取代pq.push({distance_[v],v});}else if(dist+w==distance_[v]){(cnt[v]+=cnt[u])%=1000000000+7;}}}return cnt[n-1];}
};
P1144 最短路计数(洛谷)
P1144 最短路计数 - 洛谷https://www.luogu.com.cn/problem/P1144
题目描述
给出一个 N 个顶点 M 条边的无向无权图,顶点编号为 1∼N。问从顶点 1 开始,到其他每个点的最短路有几条。
输入格式
第一行包含 2 个正整数 N,M,为图的顶点数与边数。
接下来 M 行,每行 2 个正整数 x,y,表示有一条连接顶点 x 和顶点 y 的边,请注意可能有自环与重边。
输出格式
共 N 行,每行一个非负整数,第 i 行输出从顶点 1 到顶点 i 有多少条不同的最短路,由于答案有可能会很大,你只需要输出 ansmod100003 后的结果即可。如果无法到达顶点 i 则输出 0。
输入输出样例
输入 #1复制
5 7 1 2 1 3 2 4 3 4 2 3 4 5 4 5输出 #1复制
1 1 1 2 4说明/提示
1 到 5 的最短路有 4 条,分别为 2 条 1→2→4→5 和 2 条 1→3→4→5(由于 4→5 的边有 2 条)。
对于 20% 的数据,1≤N≤100;
对于 60% 的数据,1≤N≤103;
对于 100% 的数据,1≤N≤106,1≤M≤2×106。
思路
这题和上一题没啥区别哈,就是这个无权而已,那就是权重改为1就行,还有就是这个我不知道为啥卡我样例,给我TLE了,最后还是靠加速输入输出才过的,我感觉我没啥能优化的地方了,链式前向星我也用了,,奇怪。
#include<bits/stdc++.h>
using namespace std;
int n,m;
#define int long long
const int N=2e6+10;
struct edge{int to;int next;
}graph[N*2];
int cnt,head[N];
void add_edge(int u,int v){cnt++;graph[cnt].to=v;graph[cnt].next=head[u];head[u]=cnt;
}
signed main(){ios::sync_with_stdio(false);cin.tie(nullptr);cin>>n>>m; for(int i=0;i<m;i++){int u,v;cin>>u>>v;if (u == v) continue; add_edge(u,v); add_edge(v,u);}vector<int>distance_(n+1,LLONG_MAX);distance_[1]=0;priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> pq;pq.push({0,1});vector<int>cnt(n+1,0);cnt[1]=1;while(!pq.empty()){int dist=pq.top().first;int u=pq.top().second;pq.pop();if(dist>distance_[u]) continue;for(int i=head[u];i;i=graph[i].next){int to=graph[i].to;if(distance_[to]>dist+1){distance_[to]=dist+1;pq.push({distance_[to],to});cnt[to]=cnt[u];}else if(distance_[to]==dist+1){(cnt[to]+=cnt[u])%=100003 ;}}} for(int i=1;i<=n;i++){cout<<cnt[i]<<endl;}}
P1462 通往奥格瑞玛的道路
P1462 通往奥格瑞玛的道路 - 洛谷https://www.luogu.com.cn/problem/P1462
题目背景
在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量。
有一天他醒来后发现自己居然到了联盟的主城暴风城。
在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛。
题目描述
在艾泽拉斯,有 n 个城市。编号为 1,2,3,…,n。
城市之间有 m 条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。
每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。
假设 1 为暴风城,n 为奥格瑞玛,而他的血量最多为 b,出发时他的血量是满的。如果他的血量降低至负数,则他就无法到达奥格瑞玛。
歪嘴哦不希望花很多钱,他想知道,在所有可以到达奥格瑞玛的道路中,对于每条道路所经过的城市收费的最大值,最小值为多少。
输入格式
第一行 3 个正整数,n,m,b。分别表示有 n 个城市,m 条公路,歪嘴哦的血量为 b。
接下来有 n 行,每行 1 个正整数,fi。表示经过城市 i,需要交费 fi 元。
再接下来有 m 行,每行 3 个正整数,ai,bi,ci(1≤ai,bi≤n)。表示城市 ai 和城市 bi 之间有一条公路,如果从城市 ai 到城市 bi,或者从城市 bi 到城市 ai,会损失 ci 的血量。
输出格式
仅一个整数,表示歪嘴哦交费最多的一次的最小值。
如果他无法到达奥格瑞玛,输出
AFK
。输入输出样例
输入 #1复制
4 4 8 8 5 6 10 2 1 2 2 4 1 1 3 4 3 4 3输出 #1复制
10说明/提示
对于 60% 的数据,满足 n≤200,m≤104,b≤200;
对于 100% 的数据,满足 1≤n≤104,1≤m≤5×104,1≤b≤109;
对于 100% 的数据,满足 1≤ci≤109,0≤fi≤109,可能有两条边连接着相同的城市。
思路
这道题可以看出,血量是边权,那激素我们dijkstra算法里的堆里面的东西,然后又给了另一个变量那就是收费,我们可以想到二分(我没想到,我依旧是笨蛋),里收费这个变量作为二分的东西,因为要我们求收费最小是多少嘛,那我们就二分,一直找到二分后的值,里面当然有个check函数,来判断二分的方向,check里的核心代码就就是dijkstra,利用小根堆然后每次找掉血量最少的路走,然后看走完后血量是不是小于等于b,是的话说明这个二分的答案正确,我们就继续缩减范围,就这样一直重复就好了,当然也可以像题解里面用大根堆,看最后血量有没有从b减到0
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
const int M=5e4+10;
struct edge{int to;int next;int w;
}graph[M*2];
int cnt,head[N],f[N];
void add_edge(int u,int v,int w){cnt++;graph[cnt].w=w;graph[cnt].to=v;graph[cnt].next=head[u];head[u]=cnt;
}
int n,m,b;
bool check(int x){vector<int>distance_(N,-1); //如果开头和结尾已经超过了二分出来的血量就代表这个收费不是正解 if(f[1]>x||f[n]>x) return false;distance_[1]=b;priority_queue<pair<int,int>>pq;//构建大根堆 ({剩余血量,节点})pq.push({b,1});while(!pq.empty()){int dist=pq.top().first;int u=pq.top().second;pq.pop();if(dist<distance_[u]) continue;for(int i=head[u];i;i=graph[i].next){int to=graph[i].to;int w=graph[i].w;if(f[to]>x) continue;if(distance_[to]<dist-w&&dist-w>=0){//如果要走的节点to里存的最大血量可以更新distance_[to]=dist-w;pq.push({distance_[to],to});}}}return distance_[n]!=-1;//如果不等于-1说明二分出来的答案可以
}
int main(){ios::sync_with_stdio(false);cin.tie(0);cin>>n>>m>>b;int l=1e9+10,r=0;for(int i=1;i<=n;i++){cin>>f[i]; l=min(l,f[i]);r=max(r,f[i]);} for(int i=0;i<m;i++){int u,v,w; cin>>u>>v>>w;if(u==v) continue;add_edge(u,v,w);add_edge(v,u,w);}int ans=-1;while(l<=r){int mid=(l+r)/2;if(check(mid)){ans=mid;r=mid-1;}else{l=mid+1;}}if(ans==-1) cout<<"AFK";else{cout<<ans;}
}
2642. 设计可以求最短路径的图类
2642. 设计可以求最短路径的图类 - 力扣(LeetCode)https://leetcode.cn/problems/design-graph-with-shortest-path-calculator/description/
给你一个有
n
个节点的 有向带权 图,节点编号为0
到n - 1
。图中的初始边用数组edges
表示,其中edges[i] = [fromi, toi, edgeCosti]
表示从fromi
到toi
有一条代价为edgeCosti
的边。请你实现一个
Graph
类:
Graph(int n, int[][] edges)
初始化图有n
个节点,并输入初始边。addEdge(int[] edge)
向边集中添加一条边,其中edge = [from, to, edgeCost]
。数据保证添加这条边之前对应的两个节点之间没有有向边。int shortestPath(int node1, int node2)
返回从节点node1
到node2
的路径 最小 代价。如果路径不存在,返回-1
。一条路径的代价是路径中所有边代价之和。示例 1:
输入: ["Graph", "shortestPath", "shortestPath", "addEdge", "shortestPath"] [[4, [[0, 2, 5], [0, 1, 2], [1, 2, 1], [3, 0, 3]]], [3, 2], [0, 3], [[1, 3, 4]], [0, 3]] 输出: [null, 6, -1, null, 6]解释: Graph g = new Graph(4, [[0, 2, 5], [0, 1, 2], [1, 2, 1], [3, 0, 3]]); g.shortestPath(3, 2); // 返回 6 。从 3 到 2 的最短路径如第一幅图所示:3 -> 0 -> 1 -> 2 ,总代价为 3 + 2 + 1 = 6 。 g.shortestPath(0, 3); // 返回 -1 。没有从 0 到 3 的路径。 g.addEdge([1, 3, 4]); // 添加一条节点 1 到节点 3 的边,得到第二幅图。 g.shortestPath(0, 3); // 返回 6 。从 0 到 3 的最短路径为 0 -> 1 -> 3 ,总代价为 2 + 4 = 6 。提示:
1 <= n <= 100
0 <= edges.length <= n * (n - 1)
edges[i].length == edge.length == 3
0 <= fromi, toi, from, to, node1, node2 <= n - 1
1 <= edgeCosti, edgeCost <= 106
- 图中任何时候都不会有重边和自环。
- 调用
addEdge
至多100
次。- 调用
shortestPath
至多100
次。
思路
其实没啥思路哈,和上面的都一样,也就是个模版,当练手用得了
class Graph {
public:using pii=pair<int,int>;vector<vector<pii>>graph;Graph(int n, vector<vector<int>>& edges) :graph(n){for(auto e:edges){graph[e[0]].push_back({e[1],e[2]});}}void addEdge(vector<int> edge) {graph[edge[0]].push_back({edge[1],edge[2]});}int shortestPath(int node1, int node2) {vector<int>distance_(graph.size()+1,INT_MAX);priority_queue<pii,vector<pii>,greater<pii>>pq;distance_[node1]=0;pq.push({0,node1});while(!pq.empty()){auto [dist,u]=pq.top();pq.pop();if(u==node2) return dist;if(dist>distance_[u]) continue;for(auto [v,w]:graph[u]){if(w+dist<distance_[v]){distance_[v]=w+dist;pq.push({distance_[v],v});}}}return -1;}
};/*** Your Graph object will be instantiated and called as such:* Graph* obj = new Graph(n, edges);* obj->addEdge(edge);* int param_2 = obj->shortestPath(node1,node2);*/
778. 水位上升的泳池中游泳
在一个
n x n
的整数矩阵grid
中,每一个方格的值grid[i][j]
表示位置(i, j)
的平台高度。当开始下雨时,在时间为
t
时,水池中的水位为t
。你可以从一个平台游向四周相邻的任意一个平台,但是前提是此时水位必须同时淹没这两个平台。假定你可以瞬间移动无限距离,也就是默认在方格内部游动是不耗时的。当然,在你游泳的时候你必须待在坐标方格里面。你从坐标方格的左上平台
(0,0)
出发。返回 你到达坐标方格的右下平台(n-1, n-1)
所需的最少时间 。示例 1:
输入: grid = [[0,2],[1,3]] 输出: 3 解释: 时间为0时,你位于坐标方格的位置为(0, 0)。此时你不能游向任意方向,因为四个相邻方向平台的高度都大于当前时间为 0 时的水位。 等时间到达 3 时,你才可以游向平台 (1, 1). 因为此时的水位是 3,坐标方格中的平台没有比水位 3 更高的,所以你可以游向坐标方格中的任意位置示例 2:
输入: grid = [[0,1,2,3,4],[24,23,22,21,5],[12,13,14,15,16],[11,17,18,19,20],[10,9,8,7,6]] 输出: 16 解释: 最终的路线用加粗进行了标记。 我们必须等到时间为 16,此时才能保证平台 (0, 0) 和 (4, 4) 是连通的提示:
n == grid.length
n == grid[i].length
1 <= n <= 50
0 <= grid[i][j] < n2
grid[i][j]
中每个值 均无重复
思路
其实和上面那个最小体力消耗的题差不多,我们依旧是按照步骤来就行,不同的是存进去的堆的值是不一样的,其他偶数一样,看代码其实就好了
class Solution {
public:struct Node{int x;int y;int cost;Node(int x_,int y_,int cost_):x(x_),y(y_),cost(cost_){}bool operator>(const Node& other) const{return cost>other.cost;}};int move[5]={-1,0,1,0,-1};int swimInWater(vector<vector<int>>& grid) {int m=grid.size();int n=grid[0].size();vector<vector<int>> dis(m,vector<int>(n,INT_MAX));priority_queue<Node,vector<Node>,greater<Node>> hp;hp.emplace(0,0,grid[0][0]);dis[0][0]=grid[0][0];while(!hp.empty()){auto[x,y,dist]=hp.top();hp.pop();if(dist>dis[x][y])continue;if(x==m-1&&y==n-1){return dist;}for(int i=0,nx,ny;i<4;i++){nx=x+move[i];ny=y+move[i+1];if(nx>=0&&ny>=0&&nx<m&&ny<n){int nc=max(dist,grid[nx][ny]);if(nc<dis[nx][ny]){dis[nx][ny]=nc; hp.emplace(nx,ny,dis[nx][ny]);}}}}return -1;}
};
787. K 站中转内最便宜的航班
787. K 站中转内最便宜的航班https://leetcode.cn/problems/cheapest-flights-within-k-stops/
有
n
个城市通过一些航班连接。给你一个数组flights
,其中flights[i] = [fromi, toi, pricei]
,表示该航班都从城市fromi
开始,以价格pricei
抵达toi
。现在给定所有的城市和航班,以及出发城市
src
和目的地dst
,你的任务是找到出一条最多经过k
站中转的路线,使得从src
到dst
的 价格最便宜 ,并返回该价格。 如果不存在这样的路线,则输出-1
。示例 1:
输入: n = 4, flights = [[0,1,100],[1,2,100],[2,0,100],[1,3,600],[2,3,200]], src = 0, dst = 3, k = 1 输出: 700 解释: 城市航班图如上 从城市 0 到城市 3 经过最多 1 站的最佳路径用红色标记,费用为 100 + 600 = 700。 请注意,通过城市 [0, 1, 2, 3] 的路径更便宜,但无效,因为它经过了 2 站。示例 2:
输入: n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]], src = 0, dst = 2, k = 1 输出: 200 解释: 城市航班图如上 从城市 0 到城市 2 经过最多 1 站的最佳路径标记为红色,费用为 100 + 100 = 200。示例 3:
输入:n = 3, flights = [[0,1,100],[1,2,100],[0,2,500]], src = 0, dst = 2, k = 0 输出:500 解释: 城市航班图如上 从城市 0 到城市 2 不经过站点的最佳路径标记为红色,费用为 500。提示:
1 <= n <= 100
0 <= flights.length <= (n * (n - 1) / 2)
flights[i].length == 3
0 <= fromi, toi < n
fromi != toi
1 <= pricei <= 104
- 航班没有重复,且不存在自环
0 <= src, dst, k < n
src != dst
思路
整体就是个dijkstra,但是这次相当于分层图最短路了,用bfs当然也是可以的,分层图就是现在又有个另一个限制,我们要保证在k次转飞机路线内才行,所以我们就把distance数组变成二维记录走到每个节点时已经转运了几次,还有堆里面也加上这玩意,就行了,还是很有意思的哈哈
class Solution {
public:using tiii=tuple<int, int, int>;int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k) {//建图 vector<vector<pair<int,int>>> graph(n);for(auto &edge:flights){graph[edge[0]].push_back({edge[1],edge[2]});}//建堆priority_queue<tiii,vector<tiii>,greater<>>pq;//distance_表vector<vector<int>> distance_(n,vector<int>(k+2,INT_MAX));//初始化distance_[src][k+1]=0;pq.push({0,src,k+1});int ans=0;while(!pq.empty()){auto [dist,u,remain]=pq.top();pq.pop();if(u==dst) return dist;if(remain==0) continue;if(dist>distance_[u][remain]) continue; for(auto [v,w]:graph[u]){int new_remain=remain-1;if(dist+w<distance_[v][new_remain]){distance_[v][new_remain]=dist+w;pq.push({distance_[v][new_remain],v,new_remain});}}}return -1;}
};
结束咯,之后还会接着写的,记得来看哈,有啥错误可以告诉我,我去改
相关文章:
算法加训之最短路 上(dijkstra算法)
目录 P4779 【模板】单源最短路径(标准版)(洛谷) 思路 743. 网络延迟时间(力扣) 思路 1514.概率最大路径(力扣) 思路 1631.最小体力消耗路径 思路 1976. 到达目的地的方案数 …...
01 Nginx安装及基本配置
01 Nginx安装 # 官网:https://nginx.org/en/ # 点击下载图1 Nginx下载官网 # https://nginx.org/en/download.html # 全是各个平台的源码包图2 Nginx下载版本 # 找到最下面的stable and mainline(稳定版和主线版)图3 找到最下面的稳定版 # https://nginx.org/en/li…...
ABP vNext 多租户系统实现登录页自定义 Logo 的最佳实践
🚀 ABP vNext 多租户系统实现登录页自定义 Logo 的最佳实践 🧭 版本信息与运行环境 ABP Framework:v8.1.5.NET SDK:8.0数据库:PostgreSQL(支持 SQLServer、MySQL 等)BLOB 存储:本地…...
Docker 网络
目录 前言 1. Docker 网络模式 2. 默认 bridge 网络详解 (1)特点 (2)操作示例 3. host 网络模式 (1)特点 (2)操作示例 4. overlay…...
btc交易所关键需求区 XBIT反弹与上涨潜力分析
在加密货币市场的浪潮中,狗狗币(DOGE)近期的走势吸引了众多投资者的目光。根据XBIT分析,狗狗币刚刚踏入关键需求区,此前虽从高点大幅下跌了10%,但XBIT去中心化交易所平台分析师认为,短期内它有望…...
深度剖析:YOLOv8融入UNetv2 SDI模块的性能提升之旅
文章目录 一、引言二、SDI多层次特征融合模块概述(一)背景和动机(二)模块设计原理 三、SDI模块实现(一)关键代码结构(二)代码解析 四、将SDI模块融入YOLOv8(一࿰…...
图像定制大一统?字节提出DreamO,支持人物生成、 ID保持、虚拟试穿、风格迁移等多项任务,有效解决多泛化性冲突。
字节提出了一个统一的图像定制框架DreamO,支持人物生成、 ID保持、虚拟试穿、风格迁移等多项任务,不仅在广泛的图像定制场景中取得了高质量的结果,而且在适应多条件场景方面也表现出很强的灵活性。现在已经可以支持消费级 GPU(16G…...
spark数据处理练习题详解【下】
12. (单选题) def main(args: Array[String]): Unit { println(func1("张三",f1)) } def func1(name:String,fp:(________________)): String { fp(name) } def f1(s:String): String { "welcome "s } 选择填空() A.String>S…...
Vue基础(11)_条件渲染
原生css想让显示的元素隐藏,方式有以下几点: display: none; opacity: 0; visibility: hidden; 那么vue中是怎样实现元素显示/隐藏的呢? 条件渲染 v-show 写法:v-show"表达式" 判断:表达式转换为布尔值(tr…...
湖北理元理律师事务所:债务优化服务的四维创新实践
在债务问题普遍影响家庭经济稳定的当下,专业法律服务机构的价值不仅在于提供解决方案,更需构建可持续的服务生态。湖北理元理律师事务所通过“法律心理技术教育”四维服务体系,探索出一条兼顾债务化解与生活质量保障的创新路径。 服务模式创…...
ubuntu工控机固定设备usb串口号
ubuntu工控机固定设备usb串口号 1、多个USB设备的ID相同 ubuntu系统中的串口使用权限并没有对所有的用户进行开放,所以在使用代码对串口进行操作时,需要打开用户对串口的使用权限,否则在代码中会出现“串口无法打开的报错”,只有…...
MongoDB的安装及简单使用
MongoDB 是一个开源的文档型 NoSQL 数据库,由 MongoDB Inc. 开发,专为灵活性和可扩展性设计。 特点: 1.文档模型:数据以 BSON(二进制 JSON)格式存储,支持嵌套结构。 2.动态 S…...
卷积神经网络进阶:转置卷积与棋盘效应详解
【内容摘要】 本文深入解析卷积神经网络中的转置卷积(反卷积)技术,重点阐述标准卷积与转置卷积的计算过程、转置卷积的上采样作用,以及其常见问题——棋盘效应的产生原因与解决方法,为图像分割、超分辨率等任务提供理论…...
Linux进程信号(三)之信号产生2
文章目录 4. 由软件条件产生信号5. 硬件异常产生信号模拟一下除0错误和野指针异常除0错误野指针错误 总结思考一下 4. 由软件条件产生信号 SIGPIPE是一种由软件条件产生的信号,在“管道”中已经介绍过了。 软件条件不就绪,很明显这个软件条件没有直接报错ÿ…...
【AWS入门】Amazon SageMaker简介
【AWS入门】Amazon SageMaker简介 [AWS Essentials] Brief Introduction to Amazon SageMaker By JacksonML 机器学习(Machine Learning,简称ML) 是当代流行的计算机科学分支技术。通常,人们在本地部署搭建环境,以满足机器学习的要求。 AWS…...
MySQL--day2--基本的select语句
(以下内容全部来自上述课程) SQL概述 结构化查询语句 1. SQL分类 DDL:数据定义(definition)语言:create、drop、alter… DML:数据操作(manipulation)语言ÿ…...
程序代码篇---python获取http界面上按钮或者数据输入
文章目录 前言 前言 本文简单接受了python获取http界面上按钮或者数据输入...
网络安全利器:蜜罐技术详解
蜜罐是网络安全领域中一种主动防御和情报收集的重要工具。本文将深入探讨蜜罐技术的原理、类型、应用场景以及部署注意事项。 1. 什么是蜜罐? 蜜罐(Honeypot)是一种安全资源,其价值在于被探测、攻击或未经授权使用。简单来说,蜜罐就是一个诱饵系统,用来吸引黑客的注意力…...
回溯实战篇3
文章目录 前言排列全排列全排列II 棋盘问题N皇后解数独 其他递增子序列重新安排行程 前言 今天继续带大家进行回溯的实战篇3,去学习如何用回溯的方法去解决排列和棋盘以及其他用回溯方法解决的问题,最重要的就是学会回溯三部曲的构建,一文带…...
Spark 基础自定义分区器
(一)什么是分区 【复习提问:RDD的定义是什么?】 在 Spark 里,弹性分布式数据集(RDD)是核心的数据抽象,它是不可变的、可分区的、里面的元素并行计算的集合。 在 Spark 中…...
【提高+/省选−】洛谷P1495 —— 【模板】中国剩余定理(CRT)/ 曹冲养猪
见:P1495 【模板】中国剩余定理(CRT)/ 曹冲养猪 - 洛谷 题目描述 自从曹冲搞定了大象以后,曹操就开始捉摸让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲满不高兴,于是在工作中马马虎虎&a…...
系统架构设计师考前冲刺笔记-第1章-系统工程与信息系统基础
文章目录 第1章 系统工程与信息系统基础大纲13 DSS5678 BSP910 SCM11 OLAP12 OLAP14 BRP15 集成16 企业门户19 边缘计算 第1章 系统工程与信息系统基础 大纲 1 3 DSS DSS 决策支持系统 Decision Support System 5 6 7 8 BSP 9 10 SCM 注意:生产计划 11 OLAP O…...
Vue环境下数据导出Excel的全面指南
文章目录 1. 前言2. 原生JavaScript实现方案2.1 使用Blob对象和URL.createObjectURL2.2 使用Base64编码实现 3. 常用第三方库方案3.1 使用SheetJS (xlsx)3.2 使用ExcelJS3.3 使用vue-json-excel 4. 服务器端导出方案4.1 前端请求服务器生成Excel4.2 使用Web Worker处理大数据导…...
Linux下 使用 SSH 完成 Git 绑定 GitHub
文章目录 1、检查 SSH2、生成 SSH key3、添加 SSH key4、验证绑定是否成功 1、检查 SSH Git Bash 中输入ssh命令,查看本机是否安装 SSH: 2、生成 SSH key (1)输入 ssh-keygen -t rsa 命令,表示我们指定 RSA 算法生…...
Jsoup库和Apache HttpClient库有什么区别?
Jsoup 和 Apache HttpClient 是两个功能不同的库,它们在 Java 开发中被广泛使用,但用途和功能有明显的区别: Jsoup 用途:Jsoup 是一个用于解析 HTML 文档的库。它提供了非常方便的方法来抓取和解析网页内容,提取和操作…...
安全漏洞频发,如何加强防护措施?
当系统安全漏洞频发时,应从代码安全审查、自动化漏洞扫描、权限控制与访问管理、员工安全意识培训等四个关键维度加强防护。其中,代码安全审查是防止漏洞渗透的第一道防线。企业应将代码安全审查纳入CI/CD流程,实施静态代码分析和依赖包检查机…...
Text models —— BERT,RoBERTa, BERTweet,LLama
BERT 什么是BERT? BERT,全称Bidirectional Encoder Representations from Transformers,BERT是基于Transformer的Encoder(编码器)结构得来的,因此核心与Transformer一致,都是注意力机制。这种…...
CodeBuddy初探
回顾Trae 上一篇博客Trae IDE和VSCode Trae插件初探-CSDN博客,我们进行了TraeIDE和Trae插件初探,给了Trae这样一个任务: 生成一个to do list清单web页面,采用vue实现,可以在页面上进行todolist进行增删改查。 Trae的…...
spark数据处理练习题详解【上】
1. (单选题) scala中属于序列的可变的集合,可以添加,删除元素的是() A.Array B.List C.Tuple D.ListBuffer 答案及解析:D 在Scala中,属于序列的可变集合,可以添加和删除元素的是ÿ…...
sparkSQL读入csv文件写入mysql(2)
(二)创建数据库和表 接下来,我们去创建一个新的数据库,数据表,并插入一条数据。 -- 创建数据库 CREATE DATABASE spark; -- 使用数据库 USE spark;-- 创建表 create table person(id int, name char(20), age int);-- …...
产品周围的几面墙
不能把排序,当单选题做。 2025年的杭州咖啡馆,味道最浓的不是咖啡,是聊各种项目和创业的卷味。 在过去几年,聊项目的也不少,那时候带着更加浓烈的自信和松弛感,不过今年略带几分忐忑和试探的口吻。 看到网…...
【锂电池剩余寿命预测】LSTM长短期记忆神经网络锂电池剩余寿命预测(Pytorch完整源码和数据)
目录 效果一览程序获取程序内容代码分享效果一览 程序获取 获取方式一:文章顶部资源处直接下载:...
螺旋矩阵--LeetCode
题目 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 示例 1: 输入:matrix [[1,2,3],[4,5,6],[7,8,9]] 输出:[1,2,3,6,9,8,7,4,5]示例 2: 输入:matrix [[…...
湖北理元理律师事务所:债务管理的社会价值探索
债务问题从来不是孤立的经济事件,其背后牵涉家庭稳定、社会信用体系乃至区域经济发展。湖北理元理律师事务所通过五年服务数据发现:科学债务规划可使单个家庭挽回约23%的可支配收入,间接降低离婚率、心理健康问题发生率等社会成本。 债务优化…...
知识图谱(KG)与大语言模型(LLM)
知识图谱(KG)以其结构化的知识表示和推理能力,为大语言模型(LLM)的“幻觉”、知识更新滞后和可解释性不足等问题提供了有力的解决方案。反过来,LLM的强大文本理解和生成能力也为KG的构建、补全、查询和应用…...
LLM大语言模型系列1-token
一,什么是token 1,什么是token: 参考:https://en.wikipedia.org/wiki/Token https://en.wikipedia.org/wiki/Lexical_analysis#Token 我们有很多描述token的解释,建议是汇总在一起进行综合理解: 1️⃣To…...
数据清洗-案例
四)实现代码 在之前的项目的基础之上,重写去写一个包,并创建两个类:WebLogMapper和WebLogDriver类。 (1)编写WebLogMapper类 package com.root.mapreduce.weblog; import java.io.IOException; import…...
项目的部署发布和访问的流程
首先打包项目: npm run build 打包后的文件会生成在dist文件夹中,将dist文件夹需要放到服务器里面,意味着服务有dist静态资源(index.html,css/,js/,img/) 用户在浏览器输入域名&am…...
人工智能、机器学习、深度学习定义与联系
人工智能、机器学习、深度学习定义与联系目录 一、人工智能(Artificial Intelligence, AI)1、定义2、特征:3、关键阶段的概述:1. 萌芽期(1940s–1950s):理论奠基2. 形成期(1950s–19…...
Gartner《如何将生成式人工智能(GenAI)集成到应用架构》学习心得
针对软件架构师、技术专业人士如何更好的把 GenAI 如何融入解决方案,提升用户体验、生产力并带来差异化成果的趋势,Gartner发布了《Integrating GenAI Into Your Application Architecture》研究报告。 报告首先介绍了 GenAI 的发展背景,指出其已成为主流趋势,大型语言模型…...
vscode中Debug c++
在vscode中Debug ros c程序 1 在Debug模式下编译 如果用命令行catkin_make,在输入catkin_make时加上一个参数: catkin_make -DCMAKE_BUILD_TYPEDebug 或者直接修改CMakelist.txt,添加以下代码: SET(CMAKE_BUILD_TYPE "D…...
c++从入门到精通(六)--特殊工具与技术-完结篇
特殊工具与技术-完结篇 控制内存分配 重载new和delete: 如果应用程序希望控制内存分配的过程,则它们需要定义自己的operator new函数和operator delete函数。当自定义了全局的operator new函数和operator delete函数后,我们就担负起了控…...
原型链的详细解释及使用场景
一、原型链的概念 原型链是JavaScript实现继承和属性共享的核心机制。每个对象都有一个内部属性[[Prototype]](可通过proto访问),指向其原型对象。当访问对象的属性时,若对象自身不存在该属性,则会沿着原型链向上查找…...
OpenCL C C++核心对象与属性对比
基础对象对应关系 OpenCL C 对象OpenCL C 对应类型创建函数示例cl::Platformcl_platform_idclGetPlatformIDs(1, &platform, NULL)cl::Devicecl_device_idclGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL)cl::Contextcl_contextclCreateContext(NULL,…...
Azure 机器学习初学者指南
Azure 机器学习初学者指南 在我们的初学者指南中探索Azure机器学习,了解如何设置、部署模型以及在Azure生态系统中使用AutoML & ML Studio。Azure 机器学习 (Azure ML) 是一项全面的云服务,专为机器学习项目生命周期而设计&am…...
一文读懂----Docker 常用命令
Docker 是一个强大的容器化平台,广泛用于开发、测试和生产环境。通过 Docker 命令行工具(CLI),我们可以轻松管理容器、镜像、网络和卷等资源。本文将详细介绍 Docker 的常用命令,带你熟练掌握 Docker 的核心操作命令。…...
React 19 中的useRef得到了进一步加强。
文章目录 前言一 useRef 的核心原理1.1 为什么需要 useRef?1.2 基本语法 二、React 19 中 useRef 的常见用法2.1 访问 DOM 元素2.2 保存跨渲染的数据 三、React 19 中的改进ref 作为一个属性案例演示(触发子组件焦点事件) 注意 总结 前言 在 React 的世界里&#x…...
报错System.BadImageFormatException:“试图加载格式不正确的程序。 (异常来自 HRESULT:0x8007000B)”
this.hWindowControl_Player new HalconDotNet.HWindowControl();报错System.BadImageFormatException:“试图加载格式不正确的程序。 (异常来自 HRESULT:0x8007000B)” System.BadImageFormatException 错误通常是由于平台架构不匹配导致的。它意味着你正在尝试在一个平台上加…...
【图像处理基石】OpenCV中都有哪些图像增强的工具?
OpenCV 图像增强工具系统性介绍 OpenCV 提供了丰富的图像增强工具,主要分为以下几类: 亮度与对比度调整 线性变换(亮度/对比度调整)直方图均衡化自适应直方图均衡化(CLAHE) 滤波与平滑 高斯滤波中值滤波双…...
Nordic 的RTC(Real-time counter)的介绍
目录 概述 1 RTC(Real-time counter)介绍 1.1 框架结构 1.2 时钟源 1.3 分辨率与溢出和precaler 2 寄存器功能介绍 2.1 计数寄存器 2.2 事件控制功能 2.3 比较功能 2.4 读取COUNTER寄存器 概述 本文主要介绍Nordic 的RTC(Real-time…...