写在前面
如果采用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;
}