差分约束

差分约束不是差分

题目难易不安顺序,肾选

差分约束就是一些不等式组
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<<"
";
	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
",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
",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
",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
",i);
        else
            printf("No Solution
");
    }
    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
",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=='
') 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
",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
",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

求最大距离
<=
最短路
*/

原文地址:https://www.cnblogs.com/dsrdsr/p/9657671.html