Bumped!详解—(Dijkstra堆优化,优先队列实现,结构体重载运算符)

      Dijkstra堆优化算法

              朴素的Dijkstra算法复杂度一般为O(n*n)的复杂度,能够解决大部分简单的最短路问题

              而Dijkstra堆优化的复杂度为O(n*log n),其之所以能够优化是因为利用优先队列(经重载运算<后),使最小值存储在队列的头部,使每次取出的元素都是队列中最小值


      结构体重载运算符

 因为优先队列默认是最大堆,即队头元素是队列中的最大值,所以可以通过使用结构体来实现优先队列的最小堆

参考博客:https://blog.csdn.net/catglory/article/details/45584043

 

使用优先队列时,如果需要对node结点从小到大排序,有两种方法:

1:在结构体外重载结构体小于运算符

bool operator <(const Node& a,const Node& b){
    return a.v > b.v;
}  
//这里以大于重载小于是因为默认情况下,优先队列是以大的作为队首,这样一反,就可以再默认情况下使得小的作为队首

2:在结构体内重载小于运算符

struct Node{  
    int u,v;  
    bool operator < (const Node& t)const{  
        return v > t.v;  
    }  
};  

///为什么这样写我也不知道( ̄▽ ̄)" 


           当然这道题也用到了vector存储存储结构体变量,(因为对与这道题来说,对每一张机票只是用一次,所以需要遍历,并删除旧的机票那一条航道)

          所以删除操作用到了erase()函数,删除的是进入vector的最后一个结点

          push_back()函数向vector函数结构体变量中加边

          size()函数是返回vector中有多少个元素


题意:

        题意很明确,一个最短路问题,对于f个机票,遍历操作,每一次加入一个u->v的距离是0的边(注意是单向边)

         还有要注意的是本题中距离初始化的最大值为很大很大!!!开Long Long的那种!!

 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<iostream>
typedef long long ll;
const ll INF=1e10+7;    ///!!!
const int MAX=151007;

using namespace std;
int n,m,f,s,d;
int a,b,c;
struct node     ///实现优先队列
{
    int v;
    ll c;
    node(int _v=0,ll _c=0):v(_v),c(_c) {}       ///不能少
    bool operator <(const node &other)const     ///重载运算符
    {
        return c>other.c;
    }
};

struct _Edge
{
    int v;
    ll c;
    _Edge(int _v=0,ll _c=0):v(_v),c(_c) {}
};

vector<_Edge> edge[MAX];        ///开一个vector类型的结构体二维变量
bool vis[MAX];                  ///判断是否便利过
ll dis[MAX];                    ///到第i个点的最小值
void addedge(int u,int v,ll w)
{
    edge[u].push_back(_Edge(v,w));      ///建边操作,加入到vector中
}



void diji(int s)
{
    memset(vis,false,sizeof(vis));
    for(int i=0; i<n; i++)
    {
        dis[i]=INF;
    }
    priority_queue<node> q;         ///优先队列
    while(!q.empty())   q.pop();    ///每一次搜索,都需要把原先优先队列中的元素清空
    dis[s]=0;
    q.push(node(s,0));              ///起点加入队列

    while(!q.empty())
    {
        node h=q.top();
        q.pop();
        int u=h.v;
        if(vis[u])  continue;
        vis[u]=true;
        for(int i=0; i<edge[u].size(); i++)     ///对每一个与u相连的结点遍历
        {
            int t=edge[u][i].v;
            if(!vis[t]&&dis[t]>dis[u]+edge[u][i].c)
            {
                dis[t]=dis[u]+edge[u][i].c;
                q.push(node(t,dis[t]));         ///把每一个最小结点加入优先队列中
            }
        }
    }
}


int main()
{
    scanf("%d%d%d%d%d",&n,&m,&f,&s,&d);
    for(int i=0; i<m; i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        addedge(a,b,c);
        addedge(b,a,c);
    }
    int p,q;
    ll ans=INF;


        if(f!=0)
        {
         for(int i=0; i<f; i++)
         {
            scanf("%d%d",&p,&q);
            addedge(p,q,0);
            diji(s);
            ans=min(ans,dis[d]);
            edge[p].erase(edge[p].end()-1); ///删除操作

         }
        }
        else
        {
            diji(s);
            ans=min(ans,dis[d]);
        }


        printf("%lld\n",ans);
    return 0;
}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值