题解 P3371 【【模板】单源最短路径】
题目链接:Link
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;
}
本作品由happyZYM采用知识共享 署名-非商业性使用-相同方式共享 4.0 (CC BY-NC-SA 4.0) 国际许可协议(镜像(简单版)镜像(完整版))进行许可。
转载请注明出处:https://www.cnblogs.com/happyZYM/p/11379553.html (近乎)全文转载而非引用的请在文首添加出处链接。