[模板] 最短路/差分约束
最短路
SPFA
时间复杂度 \(O(nm)\), 空间复杂度 \(O(n)\).
STL队列.
ll dis[nsz];
int vi[nsz],cnt[nsz];
queue<int> qu;
bool spfa(int s)
{
rep(i,1,n)vi[i]=0,dis[i]=ninf;
qu.push(s),dis[s]=0,vi[s]=1;
int u;
while(!qu.empty()){
u=qu.front(),qu.pop(),vi[u]=0;
forg(u,i,v){
if(dis[v]>dis[u]+edge[i].v){
dis[v]=dis[u]+edge[i].v;
cnt[v]=cnt[u]+1;
if(cnt[v]>=n)return 0; //no solution
if(vi[v]==0){
qu.push(v),vi[v]=1;
}
}
}
}
return 1;
}
手写队列.
亲测比STL慢, 似乎大量的时间浪费在取模上...==
//graph
const int nsz=1e4+50,msz=500050;
ll ninf=1e17;
int n,m,s;
struct te{int t,v,pr;}edge[msz<<1];
int hd[nsz],pe=1;
void adde(int f,int t,int v){edge[++pe]=(te){t,v,hd[f]};hd[f]=pe;}
#define forg(p,i,v) for(int i=hd[p],v=edge[i].t;i;i=edge[i].pr,v=edge[i].t)
//spfa
ll dis[nsz];
int vi[nsz],cnt[nsz];
int que[nsz],qh=1,qt=0;
int qfront(){return que[qh%n];}
void qpush(int v){que[(++qt)%n]=v;}
bool spfa(int s)
{
rep(i,1,n)vi[i]=0,dis[i]=ninf;
qpush(s),dis[s]=0,vi[s]=1;
int u;
while(qh<=qt){
u=qfront(),++qh,vi[u]=0;
forg(u,i,v){
if(dis[v]>dis[u]+edge[i].v){
dis[v]=dis[u]+edge[i].v;
cnt[v]=cnt[u]+1;
if(cnt[v]>=n)return 0;
if(vi[v]==0){
qpush(v),vi[v]=1;
}
}
}
}
return 1;
}
Dijkstra
时间复杂度 \(O((n+m)\log n)\).
ll dis[nsz];
int vi[nsz];
struct tdis{int x;ll d;};
bool operator<(tdis l,tdis r){return l.d>r.d;}
void dij(){
priority_queue<tdis> pq;
rep(i,1,n)dis[i]=ninf,vi[i]=0;
dis[s]=0;
pq.push((tdis){s,0});
while(!pq.empty()){
int u=pq.top().x;pq.pop();
if(vi[u])continue;
vi[u]=1;
for(int i=h[u],v=edge[i].t;i;i=edge[i].pr,v=edge[i].t){
if(dis[v]>dis[u]+edge[i].d){
dis[v]=dis[u]+edge[i].d;
pq.push((tdis){v,dis[v]});
}
}
}
}
差分约束
对于 \(x_i - x_j \le a_i\), 它等价于三角不等式 \(x_i \le x_j + a_i\).
建有向边 \((x_j, x_i)\), 边权 \(a_i\). 跑最长路即可. 也可以边权 \(-a_i\), 跑最短路.
当跑最长路时, spfa无解的充要条件是图中存在正环, 这也等价于不等式组无解.
对于其他类似的不等式, 可以转化为上述形状.