启动:
系统学习最短路算法之无负权回路单源最短路算法:
堆优化版本dijkstra()–>java语言版
铺垫知识:
知识点(1):邻接表
e[],ne[],h[],idx,w[];
static void add(int a,int b,int c){
e[idx]=b;
ne[idx]=h[a];
w[idx]=c;
h[a]=idx++;
}
//知识点随后补充到博客
知识点(2):小根堆
static class PII{
int num;//节点编号
int distance;//节点和目标节点间的距离
PII(int num,int distance){
this.num=num;
this.distance=distance;
}
}
PriorityQueue <PII> aq=new PriorityQueue<>(Comparator.comparing(PII->PII.distance));//小根堆,类排序
算法过程:
整体思路:
算法流程:
- 初始化处理,邻接表头数组h(初始化为-1 ),距离数组dist(初始化为无穷大)
- 将源点的序号和距离一起(通过新建类实现)加入优先队列中
- 在队列不为空的前提下,抛出表头元素,并将其状态标记为true(表示已经使用过了)
- 用表头元素更新与它直接相连的点,并将其加入优先队列中
- 结束之后判断是否能够到达目标节点,若可以直接返回,不可以返回题目给定内容
鸡汤来喽(代码部分)
//之前记得定义全局变量......
public static int dijkstra(){
PriorityQueue<PII> aq=new PriorityQueue<>(Comparator.comparing(PII->PII.distance));//建立优先队列
dist[1]=0;//源点为1号节点,距离为0,其余dist为0x3f3f3f3f表示无穷大
aq.add(new PII(1,0));//将新节点加入队列中
while(!aq.isempty()){
PII temp=aq.poll();
int num=aq.num;
int distance=aq.distance;
if(st[num]==true)continue;//如果用这个点更新过其他节点,那么就直接略过!
st[num]=true;//标记当前使用的节点,之后不再使用
for(int i=h[num];i!=-1;i=ne[i]){//用当前节点,更新其他与其直接相连的节点
int j=e[i];
if(dist[j]>dist[num]+w[i]){
dist[j]=dist[num]+w[i];
aq.add(new PII(j,dist[j]));//将刚刚更新过的节点加入优先队列中
}
}
}
if(dist[n]==0x3f3f3f3f)return -1;//目标节点若为初始化的无穷大,则表示无法到达
return dist[n];
}
public static void main(String[] args) {
//这里面已经将表建好,并且初始化了h数组和dist数组
}
队列优化版本spfa()–>java语言版
铺垫知识:
算法过程:
整体思路:
算法流程
- 初始化处理,邻接表头数组h(初始化为-1 ),距离数组dist(初始化为无穷大)
- 将源点的序号加入队列中,并将其标记为true
- 在队列不为空的前提下,抛出表头元素,并将其状态标记为false
- 用表头元素更新与它直接相连的点,若发生跟新则将其加入队列中,并将状态改为true
- 结束之后判断是否能够到达目标节点,若可以直接返回,不可以返回题目给定内容
鸡汤又来喽(代码部分)
//之前记得定义全局变量......
public static void spfa(){
dist[1]=0;
Queue<Integer> q=new LinkedList<>();
q.add(1);//将源点加入队列
st[1]=true;//将状态改为使用过
while(!q.isempty()){
int t=q.poll();
st[t]=false;//从队列中抛出后,将状态改为未使用过
for(int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>dist[t]+w[i]){
dist[j]=dist[t]+w[i];
if(!st[j]){//判断更新过后的节点是否在队列中,若不存在则加入队列,并将其状态改为true
q.add(j);
st[j]=true;
}
}
}
}
}
public static void main(String[] args) {
//这里面已经将表建好,并且初始化了h数组和dist数组
}
总结:
-
dijkstra与spfa中st[]数组的作用是不一样的,dijkstra中st数组具有单调性,而spfa中st数组不具备单调性
-
记得初始化h数组和dist数组,有时候写题写顺手了,好像很自然就忘记初始化了
-
spfa从队列中使用了当前的点,会把该点pop掉,状态数组st[i] = false(说明堆中不存在了) ,更新临边之后,把临边放入队列中, 并且设置状态数组为true,表示放入队列中 。如果当前的点距离变小,可能会再次进入队列,因此可以检验负环: