Dijkstra算法+链式前向星+优先队列优化

写在前面

如果采用O(n^2)的Dijkstra算法的话,可能会遇到图中节点过多,建立二维map数组的话,数组过大开不了,并且时间复杂度较高,所以这里说一下采用链式前向星以及优先队列优化的Dijkstra算法

链式前向星

https://www.cnblogs.com/ahalei/p/3651334.html

《啊哈!算法》啊哈磊著     

写的很好的算法书,描述内容很简单很生动!

Dijkstra优先队列优化

在Dijkstra算法中,要循环num_node-1次,每一次都要找出dis数组最小的节点,然后表明该节点已经找到了最优路径,那么再以这个节点为中间转折节点,然后去更新还没有找到最优路径的节点,这样的话,我们每次进入一个循环(1~n-1),就要寻找dis最小的位置(1~n),因为每次都取的为dis中最小的数值,那么不如直接采用优先队列来维护这样一个内容,其中存放的为dis以及节点编号信息

栗子

链接:https://ac.nowcoder.com/acm/contest/283/H
来源:牛客网

题目描述

由于临近广西大学建校90周年校庆,西大开始了喜闻乐见的校园修缮工程!

然后问题出现了,西大内部有许许多多的道路,据统计有N栋楼和M条道路(单向),每条路都有“不整洁度”W,现在校方想知道从S楼到T楼的所有路径中,“不整洁度”乘积最小是多少。

由于答案可能很大,所以你需要将最后的答案109+7取模

输入描述:

第一行为四个整数N、M、S、T,意义如上。

第2至第M+1行每行表示一条道路,有三个整数,分别表示每条道路的起点u,终点v和“不整洁度”W。

输入保证没有自环,可能有重边。

其中W一定是2的整数次幂。

输出描述:

输出一个整数,表示最小的不整洁度之乘积对109+7取模的结果。

若无解请输出 -1

输入

4 4 1 3
1 2 8
1 3 65536
2 4 2
4 3 16

输出

256

题中没有要求和为最短路径,求解的为路径乘积最小,有一句话十分重要: 其中W一定是2的整数次幂 

通过这句话,我们可以将乘法转换为加法,2^3*2^9 = 2^(3+9)

我们可以在图中边存储k,k为2^k = W,这样求解出和的最短路之后,再使用快速幂就可以求解出最终的答案

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#define INF 0x3f3f3f3f
#define MAXN  50100
#define MAXM  100100

using namespace std;
const int mod = 1e9+7;
typedef long long ll;
int u[MAXM],v[MAXM],w[MAXM],head[MAXM],next1[MAXM],dis[MAXN];
bool used[MAXN];
int N,M,S,T,W,k;

struct Node
{
    int pos,cost;
    bool operator < (const Node &a)const{
        return cost > a.cost;
    }
};
ll _pow(ll x,ll temp)
{
    ll ans = 1;
    while(temp)
    {
        if(temp&1 != 0) ans = (ans * x) % mod;
        x = (x * x) % mod;
        temp >>= 1;
    }
    return ans;
}
void Add_edge(int x,int y,int val)
{
    u[k] = x;v[k] = y;w[k] = val;next1[k] = head[x];head[x] = k++;
}
int Dijkstra()
{
    memset(used,false,sizeof(used));
    memset(dis,INF,sizeof(dis));
    priority_queue<Node> q;
    Node p;
    p.cost = 0;p.pos = S;dis[S] = 0;q.push(p);
    while(!q.empty())
    {
        p = q.top();q.pop();
        if(used[p.pos])
            continue;
        used[p.pos] = true;
        k = head[p.pos];
        while(k != -1)
        {
            if(dis[v[k]] > dis[u[k]] + w[k])
            {
                dis[v[k]] = dis[u[k]] + w[k];
                if(!used[v[k]])
                {
                    p.cost = dis[v[k]];
                    p.pos = v[k];
                    q.push(p);
                }
            }
            k = next1[k];
        }
    }
    return dis[T] == INF?-1:dis[T];
}
int main()
{
    k = 0;
    int x,y;ll z;
    scanf("%d%d%d%d",&N,&M,&S,&T);
    memset(head,-1,sizeof(head));
    for(int i = 1;i <= M;i ++)
    {
        scanf("%d%d%lld",&x,&y,&z);
        Add_edge(x,y,(int)log2((double)z));
    }
    int temp = Dijkstra();
    if(temp == -1)
        printf("-1\n");
    else
        printf("%lld\n",_pow(2,temp));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/li1615882553/article/details/84502284