返回顶部

差分约束

差分约束总的有两种
因为有判环和负数,所以一般用SPFA

  1. 题目求最小值,则就是差的最大值,跑最长路,转换为\(s_i>=s_j+w\)\(add(s_j,s_i,w)\)
  2. 题目求最大值,则就是差的最小值,跑最短路,转换为\(s_i<=s_j+w\)\(add(s_j,s_i,w)\)
    有时不等式变号出现负数

判断负环时,需建超级远点0或n+1
Layout 排队布局
需建超级原点判负环,还要算出距离
注意,差分约束为有向图,所以图可能不连通,所以我们要找到题目中的隐含条件
如本题,能看出隐含条件\(s_{i+1}-s_i>=0\)这样图就连通了!!
后一个,一定大于等于前一个

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 10005;
int n,m,d,cnt,head[N],dis[N],tot[N];bool vis[N];
struct EDGE
{
	int u,to,next,w;
}edge[N*2];
void add(int u,int v,int w)
{
	edge[++cnt].u=u;
	edge[cnt].to=v;
	edge[cnt].w=w;
	edge[cnt].next=head[u];
	head[u]=cnt;
}
int spfa(int st)
{
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	queue <int> q;
	q.push(st);
	dis[st]=0;vis[st]=1;
	tot[st]++;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=edge[i].next)
		{
			int to=edge[i].to;int w=edge[i].w;
//			cout<<dis[to]<<endl;
			if(dis[to]>dis[u]+w)
			{
				dis[to]=dis[u]+w;
				if(!vis[to])
				{
					tot[to]++;
					q.push(to);
					if(tot[to]>n)
					{
						cout<<-1<<endl;
						exit(0);
					}
				}
			}
		}
	}
	if(dis[n]<0)return 1;
	return 3;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>n>>m>>d;
	for(int i=1;i<=n;i++)add(0,i,0);
	for(int i=1;i<n;i++)
	{
		add(i+1,i,0);
	}
	int a,b,w;
	for(int i=1;i<=m;i++)
	{
		cin>>a>>b>>w;//b-a<=w
		add(a,b,w);
//		add(a,b,w);
	}
	for(int i=1;i<=d;i++)
	{
		cin>>a>>b>>w;//a-b>=w -->b-a<=-w
		add(b,a,-w);
//		add(b,a,-w);
	}
	spfa(0);
	int ans=spfa(1);
	if(dis[n]==0x3f3f3f3f)
	{
		cout<<-2<<endl;
	}else
		cout<<dis[n];
	return 0;
}
/*
hack data
4 1 1
1 4 10
2 3 20
correct -1
wrong 10
*/

Intervals
这题隐含条件就更多了
设s[k]表示0~k至少选出c个整数是
\(s[b_i]-s[a_i-1]>=c_i\)
\(s[k]-s[k-1]>=0\)
\(s[k]-s[k-1]<=1\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=50005;
struct ac
{
	int u,to,w,next;
}edge[N*2];
int m,n,head[N],cnt,dis[N],tot[N];bool vis[N];
void add(int u,int v,int w)
{
	edge[++cnt].u=u;
	edge[cnt].w=w;
	edge[cnt].next=head[u];
	edge[cnt].to=v;
	head[u]=cnt;
}
inline int read()
{
	int x=0,f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
inline void write(int x){
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+48);
}
void spfa(int st)
{
	memset(dis,-0x3f,sizeof(dis));
	queue <int> q;
	q.push(st);
	dis[st]=0;vis[st]=1;
	while(q.size())
	{
		int u=q.front();q.pop();vis[u]=0;
		for(int i=head[u];i;i=edge[i].next)
		{
			int to=edge[i].to,w=edge[i].w;
			if(dis[to]<dis[u]+w)
			{
				dis[to]=dis[u]+w;
//				cout<<to<<" "<<dis[to]<<endl;
				if(!vis[to])
				{
					q.push(to);
					vis[to]=1;
				}
			}
		}
	}
}
int main()
{
	n=read();
	int a,b,c;
	int st=100000,en=-1;
	for(int i=1;i<=n;i++)
	{
		a=read();b=read();c=read();
		add(a-1,b,c);
		st=min(st,a-1),en=max(en,b);
	}
	for(int i=st;i<=en;i++)
	{	
		add(i-1,i,0);
		add(i,i-1,-1);
	}
//	for(int i=st;i<=en;i++)add(i,i+1,0);
	spfa(st);
	cout<<dis[en]<<endl;
	return 0;
}

出纳员问题
出纳员问题

image

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=50005;
struct ac
{
	int u,to,w,next;
}edge[N*2];
int m,n,head[N],cnt,dis[N],tot[N],R[25],k[N],avi[N];bool vis[N];
void add(int u,int v,int w)
{
	edge[++cnt].u=u;
	edge[cnt].w=w;
	edge[cnt].next=head[u];
	edge[cnt].to=v;
	head[u]=cnt;
}
inline int read()
{
	int x=0,f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
inline void write(int x){
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+48);
}
void clear()
{
	memset(head,0,sizeof(head));
	memset(edge,0,sizeof(edge));cnt=0;
	memset(tot,0,sizeof(tot));
}
bool spfa(int st)
{
	memset(dis,-0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	queue <int> q;
	q.push(st);
	dis[st]=0;vis[st]=1;
	tot[st]++;
	while(q.size())
	{
		int u=q.front();q.pop();vis[u]=0;
		for(int i=head[u];i;i=edge[i].next)
		{
			int to=edge[i].to,w=edge[i].w;
			if(dis[to]<dis[u]+w)
			{
				dis[to]=dis[u]+w;
//				cout<<to<<" "<<dis[to]<<endl;
				if(!vis[to])
				{
					tot[to]++;
					q.push(to);
					vis[to]=1;
					if(tot[to]>n)return false;
				}
			}
		}
	}
	return true;
}
void buildedge(int least)
{
	for(int t=1;t<=8;t++)
	{
		add(t+16,t,R[t]-least);
	}
	for(int t=9;t<=24;t++)
	{
		add(t-8,t,R[t]);
	}
	add(0,24,least);
	
}
int main()
{
	int T;
	T=read();
	while(T--)
	{
		memset(R,0,sizeof(R));
		memset(k,0,sizeof(k));
		memset(avi,0,sizeof(avi));
		int sum=0;
		for(int i=1;i<=24;i++)
		{
			R[i]=read();
			sum+=R[i];
		}
		n=read();
		for(int i=1;i<=n;i++)
		{
			k[i]=read();
			k[i]++;avi[k[i]]++;
		}
		int i=n;
		if(sum==0)
		{
			cout<<0<<endl;continue;
		}
		for(i=n;i>=0;i--)
		{
			clear();
			for(int t=1;t<=24;t++)
			{
				add(t,t-1,-avi[t]);
				add(t-1,t,0);
			}
			buildedge(i);
			if(!spfa(0))
			{
				break;
			}
		}
		if(i==n)
		{
			cout<<"No Solution"<<endl;
		}
		else
		{
			cout<<i+1<<endl;
		}
	}
	return 0;
}
posted @ 2024-03-22 11:16  wlesq  阅读(3)  评论(0编辑  收藏  举报