堆优化 dij

1.复习邻接表

链表结构,将每个点x出发的邻边链起来,用hd[x]记录每个条边的编号,说明这些边号是与x相关的。
链表:
原型:

struct P{
    int to,nxt,dis;
}line[MAXM]//如果是无向图,数组大小为MAXN*2

初始化:

    memset(hd,0,sieof hd);
    num=0;

添加:

void add(int x,int y,int z){//x到y有距离为z的单向边(数列前向星)
    num++;
    line[num].dis = z;
    line[num].nxt = hd[x];
    line[num].to  = y;
    hd[x]=num;
}

遍历:

for(int i=hd[u];i!=-1;i=line[i].nxt){
    ...
}

2.复习堆

  1. 定义:priority_queuedl;
    整型优先队列。
    默认大根堆
  2. 相关语法:
dl.push(...);   
...=dl.top();   
dl.pop();   
dl.empty();   
dl.size();  
  1. 堆排序
#include<queue>
#include<iostream>
#include<cstdio>
using namespace std;
priority_queue <int> q;
int x;
int main(){
int n;scanf("%d",&n);
for(int i=1;i<=n;i++){
  scanf("%d",&x);
  q.push(x);
}
for(int i=1;i<=n;i++){
  printf("%d ",q.top());
  q.pop();
}
}

4.大变小

priority_queue<int,vector<int>,greater<int> > dl; 
  

0

bool operator < (const Node& x)const{
  return dis > x.dis;
}

3.dij

1.基于贪心的想法
2.以1为起点,所有点当中一定至少可以确定一条最短路,即这条最短路不会被其他点再次更新。

3.之后又会诞生至少一条最短路,用其更新别的点,此后所有边中一定又会诞生出一条最短路

4.以此类推

堆优化

因为每次都找已经是最短路的点,考虑用堆实现,o(n)->o(logn)
每次找已经是最短路的一点,去更新他点(松弛)
但是考虑一个点会被多次更新,入堆,因此堆中会存留不是最短路的点。而这个点一旦松弛完别人它的使命就结束了。堆中他的 “余党”就不能松弛别人了。

板子

#include<bits/stdc++.h>

using namespace std;
int num;
int n,m,s;
int x,y,z;
int dis[100005],vis[100005];
int hd[100005];
struct P{
  int dis,to,nxt;
}line[200005];
void add(int x,int y,int z){
  num++;
  line[num].dis =z;
  line[num].nxt =hd[x];
  line[num].to =y;
  hd[x]=num;
}
struct Node{
  int id,dis;
  bool operator < (const Node& x)const{
      return dis > x.dis ;
  }
  Node(){}
  Node(int x,int y){id=x,dis=y;}
};
priority_queue<Node> dl;
void dij(){
  while(!dl.empty()){
      Node l=dl.top();
      dl.pop();
      int u=l.id ,v=l.dis ;
      if(vis[u])continue;
      vis[u]=1;
      for(int i=hd[u];i!=-1;i=line[i].nxt ){
          if(dis[line[i].to ]>dis[u]+line[i].dis ){
              dis[line[i].to ]=dis[u]+line[i].dis;
              dl.push(Node(line[i].to ,dis[line[i].to ]));
          }
      }
  }
}
int main() {
  cin>>n>>m>>s;
  memset(hd,-1,sizeof hd);
  for(int i=1;i<=m;i++){
      cin>>x>>y>>z;
      add(x,y,z);
  }
  memset(dis,0x3f,sizeof dis);
  dis[s]=0;
  dl.push(Node(s,0));
  dij();
  for(int i=1;i<=n;i++){
      cout<<dis[i]<<' ';
  }
  return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值