堆优化Dijkstra+向前星存图+超级起点/终点(牛客——星球游戏题解)

堆优化Dijkstra+向前星存图+超级起点/终点(牛客——星球游戏题解)

题目链接

题意

n个结点,m条边构成的图,其中牛牛有一定数量的点,牛妹也有一定数量的点,现在问从牛牛中任选一点到牛妹的任意一点的最短距离是多少?
其中给定牛牛拥有的点数,牛妹拥有的点数,给出相应的图结构,已经图的节点数。

题解

考虑这个问题,从牛牛中任选一点到牛妹的任意一点的最短距离,显然是考虑最短路算法(Dijkstra即可)但是如果朴素的Dijkstra的话肯定会超时,于是考虑堆优化的Dijkstra算法,同时图比较大,于是采用向前星存图

然后再想,是不是需要跑p遍dijkstra呢(p为牛牛的结点数),显然这样是没有必要的。
直接设一不存在的结点为终点,例如0,向牛牛所拥有的所有点建单向边,边的权值为0;
设一不存在的点为终点,例如:n+1,牛妹所拥有的所有点向设的点建单向边,边的权值为0。
类似于超级起点和超级终点。

于是直接对超级起点跑一遍Dijkstra即可。

AC代码(cpp)
class Solution {
static const int maxn=1e5+5;
static const int maxm=5e5+5;
static const int inf=0x3f3f3f3f;
struct e{
    int to,nxt,val;
}edge[maxm];
int head[maxn],tot;
int dis[maxn],vis[maxn];
struct node{
    int index,dist;
    bool operator <(const node &b) const{
        return dist>b.dist;
    }
};
public:
    void init(){
        memset(head,-1,sizeof(head));
        tot=0;
    }
    void add(int u,int v,int c){
        edge[++tot].to=v;
        edge[tot].val=c;
        edge[tot].nxt=head[u];
        head[u]=tot;
    }
    int dijsktra(int s,int e,int n){
        memset(dis,inf,sizeof(dis));
        memset(vis,0,sizeof(vis));
        dis[s]=0;
        priority_queue<node> q;
        q.push(node{s,0});
        while(!q.empty()){
            node x=q.top();
            q.pop();
            int u=x.index;
            if(vis[u]) continue;
            vis[u]=1;
            for(int i=head[u];i!=-1;i=edge[i].nxt){
                int v=edge[i].to,c=edge[i].val;
                if(dis[v]>dis[u]+c){
                    dis[v]=dis[u]+c;
                    q.push(node{v,dis[v]});
                }
            }
        }
        return dis[e];
    }
    /**
     *
     * @param niuniu int整型vector 牛牛占领的p个星球的编号
     * @param niumei int整型vector 牛妹占领的q个星球的编号
     * @param path int整型vector<vector<>> m条隧道,每条隧道有三个数分别是ui,vi,wi。ui,vi分别是隧道的两边星球的编号,wi是它们之间的距离
     * @param nn int整型 星球个数n
     * @return int整型
     */
    int Length(vector<int>& niuniu, vector<int>& niumei, vector<vector<int> >& path, int nn) {
        // write code here
        init();
        int s=0,e=nn+1;
        for(int i=0;i<niuniu.size();i++){
            add(s,niuniu[i],0);
        }
        for(int i=0;i<niumei.size();i++){
            add(niumei[i],e,0);
        }
        for(int i=0;i<path.size();i++){
            int u=path[i][0],v=path[i][1],c=path[i][2];
            //cout<<u<<' '<<v<<' '<<c<<endl;
            add(u,v,c);add(v,u,c);
        }
        int ans=dijsktra(s,e,nn);
        if(ans==inf) return -1;
        return ans;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dijkstra算法是一种用于解决单源最短路径问题的经典算法,而二叉堆是一种常用的数据结构,用于实现Dijkstra算法中的优先队列。下面是Dijkstra算法结合二叉堆的Python代码实现: ```python import heapq def dijkstra(graph, start): # 初始化距离字典,用于记录起点到各个节点的最短距离 distances = {node: float('inf') for node in graph} distances[start] = 0 # 初始化优先队列,用于储待处理的节点 queue = [(0, start)] while queue: # 弹出当前最小距离的节点 current_distance, current_node = heapq.heappop(queue) # 如果当前节点已经被处理过,则跳过 if current_distance > distances[current_node]: continue # 遍历当前节点的邻居节点 for neighbor, weight in graph[current_node].items(): distance = current_distance + weight # 如果通过当前节点到达邻居节点的距离更短,则更新最短距离并加入优先队列 if distance < distances[neighbor]: distances[neighbor] = distance heapq.heappush(queue, (distance, neighbor)) return distances ``` 上述代码中,`graph`表示的邻接表表示,`start`表示起点。`distances`字典用于记录起点到各个节点的最短距离,初始时将所有节点的距离设为无穷大,起点的距离设为0。`queue`优先队列用于储待处理的节点,初始时将起点加入队列。 在算法的主循环中,每次从优先队列中弹出当前最小距离的节点,然后遍历其邻居节点。如果通过当前节点到达邻居节点的距离更短,则更新最短距离并将邻居节点加入优先队列。 最后,返回`distances`字典,即起点到各个节点的最短距离。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值