关于SPFA的优化

SPFA算法有两种优化算法 SLF 和 LLL
SLF:Small Label First 大概是双向队列?
如果要加入的元素v的距离dis[v]比当前的队首元素dis[q[head]]小的话,那么就把当前元素插到队首。
如果是手打队列的话,就先head-2,再q[head+1]=v;
LLL:Large Label Last
如果队列q的队首元素为x,队列中所有元素的平均距离为dist,如果dis[x]>dist,则将它移动到末尾,如果有一个元素的dis[x]<=dist,则将它出队。

贴个板:
(两个优化都有加)
(以bzoj 4152 为例 题面就不贴了)
但这道题跟SPFA有仇,SPFA应该是过不了的,要用dijkstra+堆优化

//这道题是有多看不起SPFA 
//SLF && LLL
//然而有什么用呢 还是T掉了 
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ms(x,y) memset(x,y,sizeof(x))
#include<queue>
#define ll long long
using namespace std;

const int N = 200000 + 10;
const int M = N*4;

inline ll read()
{
    ll data=0,w=1; char ch=0;
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();
    return data*w;
}

int n;
deque<int> q;

struct Node{
    ll x,y;
    int i;
}a[N];

struct node{
    int pre,v;
    ll w;
}edge[M];

int num=0;
int head[N];

void addedge(int from,int to,ll w){
    num++;
    edge[num].pre=head[from];
    edge[num].v=to;
    edge[num].w=w;
    head[from]=num;
}

bool cmp1(const Node &a,const Node &b){
    return a.x<b.x;
}

bool cmp2(const Node &a,const Node &b){
    return a.y<b.y;
}

void getmap(){
    sort(a+1,a+n+1,cmp1);
    for(register int i=2;i<=n;i++){
        ll w=a[i].x-a[i-1].x;
        addedge(a[i-1].i,a[i].i,w);
        addedge(a[i].i,a[i-1].i,w);
    }
    sort(a+1,a+n+1,cmp2);
    for(register int i=2;i<=n;i++){
        ll w=a[i].y-a[i-1].y;
        addedge(a[i-1].i,a[i].i,w);
        addedge(a[i].i,a[i-1].i,w);
    }   
}

ll dis[N];
bool exist[N];
int tot;
ll sum=0;
void SPFA(){
    ms(dis,127);ms(exist,0);
    q.push_back(1),dis[1]=0,exist[1]=true,tot=1;
    while(!q.empty()){
        int u=q.front();q.pop_front();
        if(dis[u]*tot>sum){
            q.push_back(u);
            continue;
        }
        exist[u]=false;tot--,sum -= dis[u];
        for(int i=head[u];i;i=edge[i].pre){
            int v=edge[i].v;
            if(dis[v]>dis[u]+edge[i].w){
                dis[v]=dis[u]+edge[i].w;
                if(!exist[v]){
                    exist[v]=true;
                    if(!q.empty()&&dis[v]<dis[q.front()]) q.push_front( v ) ;
                    else q.push_back(v);
                    tot++,sum+=dis[v];
                }
            }
        }
    }
}

int main(){
    scanf("%d",&n);
    for(register int i=1;i<=n;i++){
        a[i].x=read(),a[i].y=read();
        a[i].i=i;
    }
    getmap();
/*  for(int i=head[1];i;i=edge[i].pre){
        int v=edge[i].v;
        printf("%d %d\n",v,edge[i].w);
    }*/
    SPFA();
    printf("%lld",dis[n]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值