题解 P3371 【【模板】单源最短路径】

Solution

我这篇题解主要是对SPFA采用SLF和LLL贪心优化,具体解释详见代码:原文

#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn=10005;
const int maxm=500005;
const ll oo=2147483647;
struct char_reader
{
    FILE* f;
    char *buf,*p1,*p2;
    int size;
    char_reader(FILE* fin,int bufsize=65536)
    {
        f=fin;
        size=bufsize;
        p1=p2=0;
        buf=new char[bufsize];
    }
    inline int operator()()
    {
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,size,f),p1==p2)?EOF:*p1++;
    }
};
struct char_writer
{
    FILE* f;
    char *buf,*p,*end;
    char_writer(FILE* fout,int bufsize=65536)
    {
        f=fout;
        buf=new char[bufsize];
        p=buf;
        end=buf+bufsize;
    }
    ~char_writer()
    {
        fwrite(buf,p-buf,1,f);
    }
    inline char operator()(char ch)
    {
        return end==p&&(fwrite(buf,end-buf,1,f),p=buf),*p++=ch;
    }
};
char_reader gch(stdin);
char_writer wch(stdout);
inline void read(int &x)
{
    bool f=true;int ch;
    x=0;
    while(ch=gch(),!(ch=='-'||ch>='0'&&ch<='9'));
    if(ch=='-') f=false,ch=gch();
    x=ch-'0';
    while(ch=gch(),ch>='0'&&ch<='9') x=x*10+ch-'0';
    if(!f) x=-x;
}
inline int write(ll x)
{
    if(x==0) return wch('0');
    if(x<0) wch('-'),x=-x;
    static char buf[20],top;
    top=0;
    while(x>0) buf[top++]=x%10+'0',x/=10;
    while(top>0) wch(buf[--top]);
}//快读
struct Edge
{
    int to;
    ll dist;
    Edge *next;
};
ll d[maxn];
bool vis[maxn];
Edge *e[maxn],mem[maxm],*ecnt=mem;
int n,m,s;
inline void AddEdge(int from,int to,ll dist)
{//链式向前星
    ecnt->to=to; ecnt->dist=dist; ecnt->next=e[from];
    e[from]=ecnt++;
}
class deque
{//双端队列,用于实现SLF和LLL贪心优化(STL有点儿慢)
    private:
        int Size;
        int Q[maxn];
        int head,tail;
    public:
        inline int size() { return Size; }
        inline int front() { return Q[head]; }
        inline void pop_front()
        {
            Size--;
            head=(head+1)%maxn;
        }
        inline void push_front(int v)
        {
            Size++;
            head=(head-1+maxn)%maxn;
            Q[head]=v;
        }
        inline void push_back(int v)
        {
            Size++;
            Q[tail]=v;
            tail=(tail+1)%maxn;
        }
    deque() { Size=head=tail=0; }
};
int main()
{
#ifdef local
    freopen("pro.in","r",stdin);
#endif
//  scanf("%d%d%d",&n,&m,&s);
    read(n);read(m);read(s);
    for(int i=1;i<=n;i++) d[i]=oo;
    d[s]=0;
    int f,t,dist;
    ll sum=0;
    for(int i=0;i<m;i++)
    {
//      scanf("%d%d%lld",&f,&t,&dist);
        read(f);read(t);read(dist);
        AddEdge(f,t,dist);
    }
    deque Q;
    Q.push_back(s);
    vis[s]=true;
    while(Q.size())
    {
        int u;
        while(true)
        {
            u=Q.front();Q.pop_front();
            if(d[u]*Q.size()<=sum) break;
            Q.push_back(u);
        }
/*
LLL:Large Label Last 策略,设队首元素为i,队列中所有dist值的平均值为x,
若dist(i)>x则将i插入到队尾,查找下一元素,直到找到某一i使得dist(i)<=x,则将i出对进行松弛操作。
*/
        vis[u]=false;
        sum-=d[u];
        for(Edge *it=e[u];it;it=it->next)
            if(d[it->to]>d[u]+it->dist)
            {
                if(!vis[it->to])
                {
                    d[it->to]=d[u]+it->dist;
                    if(Q.size()>0&&d[Q.front()]>d[it->to]) Q.push_front(it->to);
                    else Q.push_back(it->to);
//SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将j插入队首,否则插入队尾。
                    vis[it->to]=true;
                    sum+=d[it->to];
                }
                else
                {
                    sum-=d[it->to];
                    d[it->to]=d[u]+it->dist;
                    sum+=d[it->to];
                }
            }
    }
    for(int i=1;i<=n;i++)
        write(d[i]),wch(' ');
    wch('\n');
    return 0;
}

转载于:https://www.cnblogs.com/happyZYM/p/11379553.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值