差分约束_训练总结

关于建边,如果需要求最小值(即最长路),一开始的话add(v,u,-w);
另外如果xi-xj<=k,那么建边(j,i,k)这个样子

 推荐博客:https://blog.csdn.net/consciousman/article/details/53812818

洛谷P5960:https://www.luogu.com.cn/problem/P5960

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '
'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=1e5+5;
int tot,head[maxn];
struct E{
    int to,next,w;
}edge[maxn<<1];
void add(int u,int v,int w){
    edge[tot].to=v;
    edge[tot].w=w;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int n,m;
int d[maxn],inq[maxn],cnt[maxn];
bool SPFA(int s){
    queue<int> q;
    q.push(s);d[s]=0,inq[s]=1;
    while(!q.empty()){
        int now=q.front();q.pop();
        inq[now]=0;
        for(int i=head[now];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(d[v]>d[now]+edge[i].w){
                d[v]=d[now]+edge[i].w;
                cnt[v]=cnt[now]+1;
                if(cnt[v]>=n) return true;
                if(inq[v]==1) continue;
                q.push(v);
            }
        }
    }
    return false;
}
int main(){
    cin>>n>>m;mem(head,-1);
    rep(i,1,m){
        int u,v,w;cin>>u>>v>>w;
        add(v,u,w);
    }
    rep(i,1,n) add(0,i,0);
    mem(d,INF);
    if(SPFA(0)) puts("NO");
    else{
        rep(i,1,n){
            cout<<d[i]<<" ";
        }
        puts("");
    }
}
View Code

求最小值(SPFA最长路),洛谷P1250种树

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '
'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=1e5+5;
int tot,head[maxn];
struct E{
    int to,next,w;
}edge[maxn<<1];
void add(int u,int v,int w){
    edge[tot].to=v;
    edge[tot].w=w;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int n,m;
int d[maxn],inq[maxn],cnt[maxn];
queue<int> q;
bool SPFA(int s){
    q.push(s);d[s]=0,inq[s]=1;
    while(!q.empty()){
        int now=q.front();q.pop();
        inq[now]=0;
        for(int i=head[now];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(d[v]<d[now]+edge[i].w){
                d[v]=d[now]+edge[i].w;
                cnt[v]++;
                if(cnt[v]>=n) return true;
                if(!inq[v]){
                    inq[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return false;
}
int main(){
    cin>>n>>m;mem(head,-1);
    rep(i,1,m){
        int u,v,w;cin>>u>>v>>w;
        add(u-1,v,w);
    }
    mem(d,-INF);
    rep(i,1,n){
        add(i-1,i,0);
        if(i!=0) add(i,i-1,-1);
    }
    rep(i,0,n) add(n+1,i,0);
    SPFA(n+1);
    cout<<d[n]<<endl;
}
View Code

洛谷P2294,这个题限定条件 w<=Xv-X(u-1)<=W,所以建边要注意了

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '
'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=1e5+5;
int tot,head[maxn];
struct E{
    int to,next,w;
}edge[maxn<<1];
void add(int u,int v,int w){
    edge[tot].to=v;
    edge[tot].w=w;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int n,m;
int d[maxn],inq[maxn],cnt[maxn];
queue<int> q;
bool SPFA(int s){
    q.push(s);d[s]=0,inq[s]=1;
    while(!q.empty()){
        int now=q.front();q.pop();
        inq[now]=0;
        for(int i=head[now];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(d[v]>d[now]+edge[i].w){
                d[v]=d[now]+edge[i].w;
                cnt[v]=cnt[now]+1;
                if(cnt[v]>=n) return true;
                if(inq[v]==1) continue;
                q.push(v);
            }
        }
    }
    return false;
}
int main(){
    int T;cin>>T;
    while(T--){
        mem(d,INF);mem(cnt,0);mem(inq,0);mem(head,-1),tot=0;
        while(!q.empty()) q.pop();
        cin>>n>>m;
        rep(i,1,m){
            int u,v,w;cin>>u>>v>>w;
            add(v,u-1,-w);
            add(u-1,v,w);
        }
        rep(i,0,n){
            add(n+1,i,0);
        }
        if(SPFA(n+1))puts("false");
        else puts("true");
    }
}
View Code

洛谷P3275
这里因为是求最小数,需要建立最长路跑SPFA,建图过程和之前的那些不太一样,SPFA算法里的cnt统计以及的松弛过程都不一样。
这道题坑很多,倒叙从n~1建可以玄学不被卡常

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '
'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=2e5+5;
int tot,head[maxn];
struct E{
    int to,next,w;
}edge[maxn<<1];
void add(int u,int v,int w){
    edge[tot].to=v;
    edge[tot].w=w;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int n,m;
int d[maxn],inq[maxn],cnt[maxn];
queue<int> q;
bool SPFA(int s){
    q.push(s);d[s]=0,inq[s]=1;
    while(!q.empty()){
        int now=q.front();q.pop();
        inq[now]=0;
        for(int i=head[now];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(d[v]<d[now]+edge[i].w){
                d[v]=d[now]+edge[i].w;
                cnt[v]++;
                if(cnt[v]>=n) return true;
                if(!inq[v]){
                    inq[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return false;
}
int main(){
    scanf("%d%d",&n,&m);mem(head,-1);
    rep(i,1,m){
        int op,a,b;scanf("%d%d%d",&op,&a,&b);
        if(op%2==0&&a==b){puts("-1");return 0;}
        if(op==1){add(b,a,0);add(a,b,0);}
        if(op==2){add(a,b,1);}
        if(op==3){add(b,a,0);}
        if(op==4){add(b,a,1);}
        if(op==5){add(a,b,0);}
    }
    per(i,n,1) add(0,i,1);
    if(SPFA(0)){puts("-1");}
    else{
        ll ans=0;
        rep(i,1,n){
            ans+=d[i];
        }
        cout<<ans<<endl;
    }
}
View Code
原文地址:https://www.cnblogs.com/Anonytt/p/13322603.html