[模板] 最短路/差分约束

最短路

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无解的充要条件是图中存在正环, 这也等价于不等式组无解.

对于其他类似的不等式, 可以转化为上述形状.

原文地址:https://www.cnblogs.com/ubospica/p/10427648.html