• A*算法求第k短路


    话不多说先上例题。。

    acwing:178. 第K短路

    给定一张 NN 个点(编号 1,2…N1,2…N),MM 条边的有向图,求从起点 SS 到终点 TT 的第 KK 短路的长度,路径允许重复经过点或边。

    注意: 每条最短路中至少要包含一条边。

    输入格式

    第一行包含两个整数 NN 和 MM。

    接下来 MM 行,每行包含三个整数 A,BA,B 和 LL,表示点 AA 与点 BB 之间存在有向边,且边长为 LL。

    最后一行包含三个整数 S,TS,T 和 KK,分别表示起点 SS,终点 TT 和第 KK 短路。

    输出格式

    输出占一行,包含一个整数,表示第 KK 短路的长度,如果第 KK 短路不存在,则输出 −1−1。

    数据范围

    1≤S,T≤N≤10001≤S,T≤N≤1000,
    0≤M≤1040≤M≤104,
    1≤K≤10001≤K≤1000,
    1≤L≤1001≤L≤100

    输入样例:
    1. 2 2
    2. 1 2 5
    3. 2 1 4
    4. 1 2 2
    输出样例:
    14

     思路:

    整体思路就是先逆向求一次dijkstral,将各点到目标点的最短路求出来,以此作为A*的估计值。然后在采用A*求第K短路,当第K次目标点出队列是,返回值即可。注意起点终点一直时需要将k+1,将原地不动的情况除去。

    上代码:

    1. #include
    2. using namespace std;
    3. typedef pair<int,int> PII;
    4. typedef pair<int,PII> PIII;
    5. #define y second
    6. #define x first
    7. const int N=1010,M=3e4+10;
    8. int s, t ,k;
    9. int n,m;
    10. int h[N],h2[N],e[M],ne[M],w[M],idx;
    11. int dis[N],cnt[N];
    12. bool st[N];
    13. void add(int h[],int a,int b,int c){
    14. e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
    15. }
    16. void dijkstral(){
    17. memset(dis,0x3f,sizeof(dis));
    18. priority_queue,greater>q;
    19. dis[t]=0;
    20. q.push({0,t});
    21. while(q.size()){
    22. auto T=q.top();
    23. q.pop();
    24. int u=T.y;
    25. if(st[u]){
    26. continue;
    27. }
    28. st[u]=true;
    29. for(int i=h2[u];~i;i=ne[i]){
    30. int j=e[i];
    31. if(st[j]){
    32. continue;
    33. }
    34. if(dis[j]>dis[u]+w[i]){
    35. dis[j]=dis[u]+w[i];
    36. q.push({dis[j],j});
    37. }
    38. }
    39. }
    40. }
    41. int astar(){
    42. priority_queue,greater> q;
    43. q.push({dis[s],{0,s}});
    44. while(q.size()){
    45. auto T=q.top();
    46. q.pop();
    47. int dist=T.y.x;
    48. int u=T.y.y;
    49. cnt[u]++;
    50. if(cnt[t]==k){
    51. return dist;
    52. }
    53. for(int i=h[u];~i;i=ne[i]){
    54. int j=e[i];
    55. if(cnt[j]>k){
    56. continue;
    57. }
    58. q.push({dist+w[i]+dis[j],{dist+w[i],j}});
    59. }
    60. }
    61. return -1;
    62. }
    63. int main()
    64. {
    65. ios::sync_with_stdio(0);
    66. cin.tie(0),cout.tie(0);
    67. memset(h,-1,sizeof(h));
    68. memset(h2,-1,sizeof(h2));
    69. cin>>n>>m;
    70. for(int i=1;i<=m;i++){
    71. int a,b,c;
    72. cin>>a>>b>>c;
    73. add(h,a,b,c);
    74. add(h2,b,a,c);
    75. }
    76. cin>>s>>t>>k;
    77. dijkstral();
    78. if(s==t){
    79. k++;
    80. }
    81. int ans=astar();
    82. cout<
    83. }

     这里附上一道例题,求次短路。。

    算是A*的特殊情况了,去直接秒杀吧。

    acwing:133. 第二短路

    贝茜把家搬到了一个小农场,但她常常回到 FJ 的农场去拜访她的朋友。

    贝茜很喜欢路边的风景,不想那么快地结束她的旅途,于是她每次回农场,都会选择第二短的路径,而不像我们所习惯的那样,选择最短路。

    贝茜所在的乡村有 RR 条双向道路,每条路都连接了所有的 NN 个农场中的某两个。

    贝茜居住在农场 11,她的朋友们居住在农场 NN(即贝茜每次旅行的目的地)。

    贝茜选择的第二短的路径中,可以包含任何一条在最短路中出现的道路,并且一条路可以重复走多次。

    当然第二短路的长度必须严格大于最短路(可能有多条)的长度,但它的长度必须不大于所有除最短路外的路径的长度。

    输入格式

    第一行包含两个整数 NN 和 RR。

    接下来 RR 行,每行包含三个整数 A,B,DA,B,D,表示农场 AA 和农场 BB 之间存在一条长度为 DD 的路。

    输出格式

    输出仅包含一个整数,表示从农场 11 到农场 NN 的第二短路的长度。

    数据范围

    1≤R≤1051≤R≤105,
    1≤N≤50001≤N≤5000,
    1≤D≤50001≤D≤5000,
    1≤A,B≤N1≤A,B≤N

    输入样例:
    1. 4 4
    2. 1 2 100
    3. 2 4 200
    4. 2 3 250
    5. 3 4 100
    输出样例:
    450
    1. #include
    2. using namespace std;
    3. const int N=5010,M=4e5+10;
    4. #define x first
    5. #define y second
    6. typedef pair<int,int>PII;
    7. typedef pair<int,PII>PIII;
    8. int h[N],e[M],ne[M],w[M],idx;
    9. int dis[N];
    10. bool st[N];
    11. int cnt[N];
    12. int n,m;
    13. void add(int a,int b,int c){
    14. e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
    15. }
    16. void dijkstral()
    17. {
    18. memset(dis,0x3f,sizeof(dis));
    19. priority_queue,greater>q;
    20. q.push({0,n});
    21. dis[n]=0;
    22. while(q.size()){
    23. auto t=q.top();
    24. q.pop();
    25. int v=t.y;
    26. if(st[v]){
    27. continue;
    28. }
    29. st[v]=true;
    30. for(int i=h[v];~i;i=ne[i]){
    31. int j=e[i];
    32. if(st[j]){
    33. continue;
    34. }
    35. if(dis[j]>dis[v]+w[i]){
    36. dis[j]=dis[v]+w[i];
    37. q.push({dis[j],j});
    38. }
    39. }
    40. }
    41. }
    42. int astar(){
    43. int flag=0;
    44. priority_queue,greater>q;
    45. q.push({dis[1],{0,1}});
    46. while(q.size()){
    47. auto t=q.top();
    48. q.pop();
    49. int v=t.y.y;
    50. int dist=t.y.x;
    51. cnt[v]++;
    52. if(cnt[n]==1){
    53. flag=dist;
    54. }
    55. if(cnt[n]>=2&&dist>flag){
    56. return dist;
    57. }
    58. for(int i=h[v];~i;i=ne[i]){
    59. int j=e[i];
    60. if(cnt[j]>2){
    61. continue;
    62. }
    63. q.push({dist+dis[j]+w[i],{dist+w[i],j}});
    64. }
    65. }
    66. }
    67. int main()
    68. {
    69. ios::sync_with_stdio(0);
    70. cout.tie(0),cin.tie(0);
    71. memset(h,-1,sizeof(h));
    72. cin>>n>>m;
    73. for(int i=1;i<=m;i++){
    74. int a,b,c;
    75. cin>>a>>b>>c;
    76. add(a,b,c);
    77. add(b,a,c);
    78. }
    79. dijkstral();
    80. int ans=astar();
    81. cout<
    82. }

     

  • 相关阅读:
    Cadence物理库 LEF 文件语法学习【持续更新】
    join、inner join、left join、right join的区别
    LoadBalance客户端负载均衡
    文档在线预览(五)在服务器部署组件来实现在线预览
    强化学习中这种loss图正常吗
    【图像配准】Canny边缘检测+模板配准红外可见光双路数据
    安卓毕业设计源码基于Uniapp+SSM实现的新闻APP
    用开源的企业办公开发平台,搭建什么样的企业网盘?
    Redis漏洞总结--未授权--沙箱绕过--(CNVD-2015-07557)&&(CNVD-2019-21763)&&(CVE-2022-0543)
    五分钟搭建ftp服务器,真的不含糊
  • 原文地址:https://blog.csdn.net/2301_80221401/article/details/143415276