1. 程式人生 > 實用技巧 >差分約束_訓練總結

差分約束_訓練總結

關於建邊,如果需要求最小值(即最長路),一開始的話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 '\n' #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 '\n'
#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-1,-w);
    }
    rep(i,1,n){
        add(i-1,i,1);
        add(i,i-1,0);
    }
    rep(i,0,n) add(n+1,i,0);
    mem(d,INF);
    SPFA(n+1);
    int minn=INF;
    rep(i,0,n){
        minn=min(minn,d[i]);
    }
    cout<<d[n]<<endl;
    cout<<d[n]-minn<<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 '\n'
#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 '\n'
#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