差分约束

差分约束不是差分

题目难易不安顺序,肾选

差分约束就是一些不等式组
a[i]-a[j]>=k1
a[i]-a[j]<=k2
差分约束系统就是一些不等式的组,而我们的目标是通过给定的约束不等式组求出最大值或者最小值或者差分约束系统是否有解。
这个就可以转化为图论求解

T1 poj 3169

题目

/*
不等式 1
b1-a1>=x
b2-a2<=x
求最大值
全部化为<=
b2-a2<=x
a1-b1<=-x

不等式2 
xi-x(i-1)>=0 -> x(i-1)-xi<=0

S=1
跑最短路 
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
//#define int long long
using namespace std;
const int inf=0x3f3f3f3f;
const int maxm=20007;
const int maxn=1007;
int n,ml,md;
int dis[maxn];
int ru[maxn],vis[maxn];
struct edge {
    int v,q,nxt;
}e[maxm];
int head[maxm],tot;
void add_edge(int u,int v,int q) {
    //cout<<u<<" "<<v<<" "<<q<<"\n";
    e[++tot].v=v;
    e[tot].q=q;
    e[tot].nxt=head[u];
    head[u]=tot;
}
void zzdsr(int u,int v,int q,int pd) {//1为<= 0为>= 
    !pd ? add_edge(u,v,q):add_edge(v,u,-q);
}
void spfa() {
    memset(dis,0x3f,sizeof(dis));
    queue<int> q;
    q.push(1);
    dis[1]=0;
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].nxt) {
            //printf("%d -> %d\n",u,e[i].v);
            int v=e[i].v;
            if(dis[v]>dis[u]+e[i].q) {
                dis[v]=dis[u]+e[i].q;
                if(!vis[v]) {
                    vis[v]=1;
                
                    //环 
                    if(ru[v]==n+1) {printf("-1");return;}
                
                    ru[v]++;
                    q.push(v);
                }
            }
        }
    }
    //无解 
    if(dis[n]==inf) puts("-2");
    //正常答案 
    else printf("%d\n",dis[n]);
}
int main()
{
    //freopen("a.in","r",stdin);
    //输入建边 
    scanf("%d%d%d",&n,&ml,&md);
    for(int i=1;i<=ml;++i) {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        a=min(a,b);
        b=max(a,b);
        zzdsr(a,b,c,0);
    }
    for(int i=1;i<=md;++i) {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        a=min(a,b);
        b=max(a,b);
        zzdsr(a,b,c,1);
    }
    
//  xi-x(i-1)>=0 -> x(i-1)-xi<=0
    for(int i=2;i<=n;++i)
        zzdsr(i-1,i,0,1);
    
    //判断1到n 
    spfa();
    return 0;   
}

T2 poj1201

题目

/*
求1到n的最小值
最长路
转化为>=
b - (a-1) >= c
{
    b - (a-1) >= c
}
0 <= xi - x(i-1) <=1
{
    x(i-1) - xi >= -1   
    xi - x(i-1) >= 0
}
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=50100;
int n;
int dis[maxn],vis[maxn];
int mi=inf,ma;
struct node {
    int v,q,nxt;
}e[maxn*100];
int head[maxn*100],tot;
void add_edge(int u,int v,int q) {
    e[++tot].v=v;
    e[tot].q=q;
    e[tot].nxt=head[u];
    head[u]=tot;
}
void spfa()
{
    for(int i=mi-1;i<=ma;++i)
        dis[i]=-0x3f3f3f3f;
    queue<int> q;
    q.push(mi-1);
    dis[mi-1]=0;
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].nxt) {
            int v=e[i].v;
            if(dis[v]<dis[u]+e[i].q) {
                dis[v]=dis[u]+e[i].q;
                if(!vis[v]) {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    printf("%d\n",dis[ma]);
}
int main()
{
    scanf("%d",&n);

    for(int i=1;i<=n;++i) {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add_edge(a-1,b,c);
        mi=min(a,mi);
        ma=max(b,ma);
    }
    for(int i=mi;i<=ma;++i) {
        add_edge(i,i-1,-1);
        add_edge(i-1,i,0);
    }
    spfa();
    return 0;
}

T3 POJ 1275

POJ 1275

#include<queue>
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=1000+100,K=30;
int s[K],r[K],h[K];
struct node
{
    int v,nxt,w;    
}e[N*10];
int head[N],ejs;
void add(int u,int v,int w) {
    e[++ejs].v=v;e[ejs].w=w;e[ejs].nxt=head[u];head[u]=ejs;
}
int dis[K],vis[K],in[K];
int spfa() {
    queue<int> q;
    memset(in,0,sizeof(in));
    memset(dis,-0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[0]=0;
    q.push(0);
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i!=-1;i=e[i].nxt) {
            int v=e[i].v;
            if(dis[v]<dis[u]+e[i].w) {
                dis[v]=dis[u]+e[i].w;
                if(!vis[v]) {
                    vis[v]=1;
                    q.push(v);
                    in[v]++;
                    if(in[v]>24) return 0;
                }
            }
        }
    }
    return 1;
}
int work(int ans) {
    ejs=0;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=24;++i)
        add(i,i-1,-h[i]),
        add(i-1,i,0);
    for(int i=1;i<=8;++i)
        add(i+16,i,r[i]-ans);
    for(int i=9;i<=24;++i)
        add(i-8,i,r[i]);
    add(0,24,ans);
    add(24,0,-ans);
    return spfa();
}
int main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--) {
        memset(r,0,sizeof(r));
        memset(h,0,sizeof(h));
        for(int i=1;i<=24;++i)
            cin>>r[i];
        int m;
        cin>>m;
        for(int i=1;i<=m;++i) {
            int x;
            cin>>x;
            h[x+1]++;
        }
        int i;
        for(i=0;i<=m;++i)
            if(work(i)) break;
        if(i<=m)
            printf("%d\n",i);
        else
            printf("No Solution\n");
    }
    return 0;
}

T4 POJ 2983

题目

/*
mc L teacher 讲的好快啊
类似网络流的套路
一个个枚举GG掉了
然后一个超级S连接每个点,q=0
这样就没有影响了

P A B X代表A站在B站北方X光年处
V A B 代表A站在B站北方,而且距离至少为1光年
以南为正方向

  B-A == X  
 =B-A >= X and B-A <= X
 =B-A >= X and A-B >= -X

  B-A >= 1
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define NO "Unreliable"
#define YES "Reliable"
const int inf=0x3f3f3f3f;
const int maxn=500007;
struct Edge {
    int v,nxt,q;
}e[maxn<<2];
int head[maxn<<2],tot;
void add_Edge(int u,int v,int q) {
    //printf("%d -> %d q=%d\n",u,v,q);
    e[++tot].v=v;
    e[tot].q=q;
    e[tot].nxt=head[u];
    head[u]=tot;
}
int n,m,dis[maxn],vis[maxn],ru[maxn];
void spfa(int S) {
    memset(dis,-0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(ru,0,sizeof(ru));
    queue<int> q;
    q.push(S);
    dis[S]=0;
    while(!q.empty()) {
        int u=q.front();q.pop(),vis[u]=0;
        for(int i=head[u];i;i=e[i].nxt) {
            int v=e[i].v;
            if(dis[v]<dis[u]+e[i].q) {
                dis[v]=dis[u]+e[i].q;
                if(!vis[v]) {
                    vis[v]=1;
                    if(ru[v]>=n) {puts(NO);return;}
                    ru[v]++;
                    q.push(v);
                }
            }
        }
    }
    puts(YES);
}
int main() {
    //freopen("a.in","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(head,0,sizeof(head));
        tot=0;
        int a,b,x;
        char s;
        for(int i=1;i<=m;++i) {
            s=getchar();
            while(s==' ' || s=='\n') s=getchar();
            if(s=='P') {
                scanf("%d%d%d",&a,&b,&x);
                add_Edge(a,b,x);
                add_Edge(b,a,-x);
            }
            else {
                scanf("%d%d",&a,&b);
                add_Edge(a,b,1);
            }
        }

        //超级虚  点 0 连接每一个点,q=0
        for(int i=1;i<=n;++i)
            add_Edge(0,i,0);

        spfa(0);
    }
    return 0;
}

T5 hdu 3340

题目

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn=121010;
const int inf=0x3f3f3f3f;
int cnt;
struct node {
    int x,id;
    bool operator < (const node &b) const {
        return x<b.x;
    }
}a[maxn];
struct edge {
    int v,nxt,q;
}e[maxn<<2];
int head[maxn<<2],tot;
void add(int u,int v,int q) {
    //printf("%d -> %d q=%d\n",u,v,q );
    e[++tot].v=v;
    e[tot].q=q;
    e[tot].nxt=head[u];
    head[u]=tot;
}
int n,d,S,T;
int dis[maxn],vis[maxn],ru[maxn];
void spfa() {
    for(int i=0;i<=n;++i)
        dis[i]=0x7fffffff;
    memset(vis,0,sizeof(vis));
    memset(ru,0,sizeof(ru));
    queue<int> q;
    q.push(S);
    dis[S]=0;
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].nxt) {
            int v=e[i].v;
            if(dis[v] > dis[u]+e[i].q) {
                dis[v]=dis[u]+e[i].q;
                if(!vis[v]) {
                    vis[v]=1;
                    if(ru[v]>n) {puts("-1");return;}
                    ru[v]++;
                    q.push(v);
                }
            }
        }
    }
    printf("%d\n",dis[T]);
}
void solve() {
    printf("Case %d: ",++cnt);
    memset(head,0,sizeof(head));tot=0;
    scanf("%d%d",&n,&d);
    for(int i=1;i<=n;++i) {
        a[i].id=i;
        scanf("%d",&a[i].x);
    }
    sort(a+1,a+1+n);
    for(int i=1;i<n;++i)
    {
        add(i+1,i,-1);
        int u = max(a[i].id, a[i+1].id), v = min(a[i].id, a[i+1].id);  
        if (u-v > d) {puts("-1");return;}
        add(v,u,d);  
    }
    S=a[1].id,T=a[n].id;
    if(S>T) swap(S,T);
    spfa();
}
int main() {
    //freopen("a.in","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}




/*
一
给定顺序的差值小于等于d
y-x<=d
二
排序之后的大小关系
高度x<y
y-x>=1
x-y<=-1

求最大距离
<=
最短路
*/
全部评论

相关推荐

09-25 10:34
东北大学 Java
多面手的小八想要自然醒:所以读这么多年到头来成为时代车轮底下的一粒尘
点赞 评论 收藏
分享
10-28 11:04
已编辑
美团_后端实习生(实习员工)
一个2人:我说几个点吧,你的实习经历写的让人觉得毫无含金量,你没有挖掘你需求里的 亮点, 让人觉得你不仅打杂还摆烂。然后你的简历太长了🤣你这个实习经历看完,估计没几个人愿意接着看下去, sdk, 索引这种东西单拎出来说太顶真了兄弟,好好优化下简历吧
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务