1. 程式人生 > >[模板] 最短路/差分約束

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

手寫 最長 隊列 空間 親測 inline 其他 復雜度 line

最短路

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無解的充要條件是圖中存在正環, 這也等價於不等式組無解.

對於其他類似的不等式, 可以轉化為上述形狀.

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