spfa优化 SLF LLL

简介:

2013.10.23 更新

之前写的时候不知道在想什么,整理模板时才发现写挫了,现在重发一个


SPFA 是按照 FIFO 的原则更新距离的, 没有考虑到距离标号的作用. 实现中 SPFA 有两个非常著名的优化: SLF 和 LLL.

  SLF: Small Label First 策略.
  实现方法是, 设队首元素为 i, 队列中要加入节点 j, 在 d_j \le d_i 时加到队首而不是队尾, 否则和普通的 SPFA 一样加到队尾. 这可以用个优先级队列维护

  LLL: Large Label Last 策略. 
  实现方法是, 设队列 Q 中的队首元素为 i, 距离标号的平均值为 \overline d = \frac {\sum_{j \in Q} d_j }{\left| Q \right|}, 每次出队时, 若 d_i > \overline d, 把 i 移到队列末尾, 如此反复, 直到找到一个 i 使 d_i \le \overline d, 将其出队.

 

/**
    复杂度分析:
        普通SPFA km kmax=n 不适合稠密图 一般为2
        优先级队列  加入节点复杂度logn 节点数太多时适得其反,对于特殊数据速度略小于普通spfa
                     对于随机图效果很好
        手动模拟SLF,LLL 复杂度低于优先级队列,最坏情况与普通SPFA持平

*/

#define Maxn 100010//最大点数
#define Maxm 400010//最大边数,无向图要建双向边
int w[Maxm],u[Maxm],next[Maxm],cnt;
int first[Maxn],havein[Maxn];//havin为入队次数
long long d[Maxn];//距离
int n;
bool in[Maxn];//队中标志
inline void add(int vn,int un,int wn){//邻接表存储
    u[cnt]=un;w[cnt]=wn;next[cnt]=first[vn];first[vn]=cnt++;
}
struct node{
    int v,dd;
    node(int &a):v(a),dd(d[a]){};
    bool operator< (const node& a)const{
        return dd>a.dd;
    }
};
priority_queue<node> q; //利用优先级队列SLF和LLL
bool spfa(int s){
    int i,now,ne,t;
    memset(in,0,sizeof(in));
    memset(havein,0,sizeof(havein));
    for(i=0;i<n;i++)d[i]=INF; //memset(d,0x3f,sizeof(d));
    d[s]=0;in[s]=1;q.push(s);
    while(!q.empty()){
        now=q.top().v;q.pop();
        if(!in[now])continue;
        in[now]=0;
        for(i=first[now];~i;i=next[i]){
            ne=u[i];
            if(d[ne]<=(t=d[now]+w[i]))continue;
            d[ne]=t; in[ne]=1; q.push(ne);
            if(++havein[ne]>n)return 0;//判断有无负环
        }
    }
    return 1;//返回1为正常,0为有负环
}
#define M 200000  //手动模拟
int q[M];
bool spfa(int s){
    int i,now,ne,t;
    memset(in,0,sizeof(in));
    memset(havein,0,sizeof(havein));
    memset(d,0x3f,sizeof(d));
    int l,r,len;l=r=len=0;
    long long sum=0;
    d[s]=0;in[s]=havein[s]=1;
    q[r++]=s;len++;
    while(l!=r){
        now=q[l++];
        if(l==M)l=0;
        if(d[now]*len>sum){//LLL
            q[r++]=now;
            if(r==M)r=0;
            continue;
        }
        len--; sum-=d[now]; in[now]=0;
        for(i=first[now];~i;i=Next[i]){
            ne=u[i];
            if(d[ne]<=(t=d[now]+w[i]))continue;
            d[ne]=t;
            if(in[ne])continue;
            in[ne]=1;
            if(t<=d[q[l]]){ //SLF
                if(--l<0)l=M-1;
                q[l]=ne;
            }
            else{
                q[r++]=ne;
                if(r==M)r=0;
            }
            len++; sum+=t;
            if(++havein[ne]>n)return 0;
        }
    }
    return 1;//返回1为正常,0为有负环
}
void init()//边初始化
{
    cnt=0;
    memset(first,-1,sizeof(first));
}


目录
相关文章
|
17天前
|
缓存 算法 搜索推荐
Java中的算法优化与复杂度分析
在Java开发中,理解和优化算法的时间复杂度和空间复杂度是提升程序性能的关键。通过合理选择数据结构、避免重复计算、应用分治法等策略,可以显著提高算法效率。在实际开发中,应该根据具体需求和场景,选择合适的优化方法,从而编写出高效、可靠的代码。
27 6
|
2月前
|
Java 编译器 程序员
Java面试高频题:用最优解法算出2乘以8!
本文探讨了面试中一个看似简单的数学问题——如何高效计算2×8。从直接使用乘法、位运算优化、编译器优化、加法实现到大整数场景下的处理,全面解析了不同方法的原理和适用场景,帮助读者深入理解计算效率优化的重要性。
41 6
|
算法 搜索推荐 Java
java基础算法系列(三)(选择排序的简单优化讲解)
java基础算法系列(三)(选择排序的简单优化讲解)
|
8月前
|
算法 容器
class034 链表高频题目和必备技巧【算法】
class034 链表高频题目和必备技巧【算法】
74 0
class034 链表高频题目和必备技巧【算法】
|
存储 算法 搜索推荐
java基础算法系列(二)冒泡排序的优化讲解(鸡尾酒算法)
java基础算法系列(二)冒泡排序的优化讲解(鸡尾酒算法)
|
移动开发 算法 搜索推荐
快速排序(Java分治法)
快速排序(Java分治法)
159 0
快速排序(Java分治法)
|
人工智能 Java
K倍区间——JAVA解法(蓝桥杯)
K倍区间——JAVA解法(蓝桥杯)
177 0
|
人工智能 算法 Java
算法_逆序对_归并(java)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
|
算法 Java
Java利用回溯实现八皇后问题
八皇后问题(英文:Eight queens),是由国际象棋棋手马克斯·贝瑟尔于1848年提出的问题,是回溯算法的典型案例。
168 0
Java利用回溯实现八皇后问题
|
算法 Java
最大交换(java,算法,贪心)
最大交换(java,算法,贪心)
103 0

热门文章

最新文章