差分约束问题

差分约束问题



区间

给定 n 个区间$ [ai,bi]$和 $n \(个整数\) ci$。

你需要构造一个整数集合 Z,使得∀i∈[1,n],Z 中满足ai≤x≤bi的整数 x 不少于 ci 个。

求这样的整数集合 Z 最少包含多少个数。

输入格式
第一行包含整数 n。

接下来n行,每行包含三个整数ai,bi,ci。

输出格式
输出一个整数表示结果。

数据范围
1≤n≤50000,
0≤ai,bi≤50000,
1≤ci≤bi−ai+1
输入样例:
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
输出样例:
6

#include<bits/stdc++.h>
using namespace std;

const int N=5e4+5;
int st,ed,m,te,tail[N],d[N];
bool vis[N];
struct e_
{
	int v,w,pre;
}e[N*3];

inline void add(int u,int v,int w)
{
	e[++te]=(e_){v,w,tail[u]};
	tail[u]=te;
}

void SPFA()
{
	memset(d,128,sizeof(d));
	deque<int>q;
	q.push_back(st);
	d[st]=0;
	
	while(q.size())
	{
		int u=q.front();
		q.pop_front();
		vis[u]=0;
		
		for(int i=tail[u];i;i=e[i].pre)
		{
			int v=e[i].v,w=e[i].w;
			if(d[v]<d[u]+w)
			{
				d[v]=d[u]+w;
				
				if(!vis[v])
				{
					vis[v]=1;
					if(q.empty()||d[q.front()]>d[v]) q.push_back(v);
					else q.push_front(v);
				}
			}
		}
	}
}

int main()
{
	scanf("%d",&m);
	st=N+5;
	for(int i=1,a,b,c;i<=m;++i)
	{
		scanf("%d %d %d",&a,&b,&c);
		add(a,b+1,c);
		st=min(st,a);
		ed=max(ed,b+1);
	}
	
	for(int i=st;i<ed;++i) 
	{
		add(i,i+1,0);
		add(i+1,i,-1);
	}
	
	
	SPFA();
	
	printf("%d",d[ed]);
}

西瓜地

题目描述
笨笨种了一块西瓜地,但这块西瓜地的种植范围是一条直线。

笨笨在一番研究过后,得出了m个结论,这 m个结论可以使他收获的西瓜最多。

笨笨的结论是这样的:

从西瓜地b处到e处至少要种植t个西瓜,这个范围的收获就可以最大化。

笨笨不想那么辛苦,所以他想种植的西瓜尽量少,而又满足每一个所得的结论。

输入格式
第一行两个数n,m,表示笨笨的西瓜地长n,笨笨得出m个结论。

接下来m行表示笨笨的m个结论,每行三个数b,e,t。

输出格式
输出笨笨最少需种植多少西瓜。

样例
样例输入

9 4
1 4 2
4 6 2
8 9 2
3 5 2

样例输出

5

数据范围与提示
\(1<=n<=5000\)

\(0<=m<=3000\)

\(1<=b<=e<=n\)

\(0<=t<=e-b+1\)

由题:

\(d(e)-d(b-1)>=t\)

\(d(i)-d(i-1)>=0\)

\(d(i)-d(i+1)>=-1\)

#include<bits/stdc++.h>
using namespace std;

const int N=5e3+5,M=8e3+5;
int t,te,n,m,tail[N],d[N];
bool vis[N];
struct e_
{
	int v,w,pre;
}e[M];

void add(int u,int v,int w)
{
	e[++te]=(e_){v,w,tail[u]};
	tail[u]=te;
}

void SPFA()
{
	memset(d,0x80,sizeof(d));
	deque<int>q;
	q.push_back(1);
	d[1]=0;
	while(q.size())
	{
		int u=q.front();
		q.pop_front();
		vis[u]=0;
//		cout<<"u-->"<<u-2<<"\n";
		for(int i=tail[u];i;i=e[i].pre)
		{
			int v=e[i].v,w=e[i].w;
			
//			cout<<"边"<<v-2<<' '<<w<<' '<<d[v];
			if(d[v]<d[u]+w)
			{
				d[v]=d[u]+w;
				if(!vis[v])
				{
					vis[v]=1;
					
					if(q.empty()||d[q.front()]>d[v]) q.push_back(v);
					else q.push_front(v);
				}
			}
//			cout<<' '<<d[v]<<"\n";
		}
	}
}

int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1,u,v,w;i<=m;++i)
	{
		scanf("%d %d %d",&u,&v,&w);
		add(u+1,v+2,w);
	}
	n+=2;
	for(int i=1;i<=n;++i) add(i,i+1,0),add(i+1,i,-1);
	
	
	SPFA();
//	for(int i=1;i<=n;++i) cout<<i-2<<"d="<<d[i]<<"\n";
	printf("%d",d[n]);
	
}

布局 Lay Out_超级原点

image-20200609171044230

为了防止存在多个连通块,并且存在负环的联通块与节点1不相连导致判断失误,添加超级原点。

1.为了保证超级原点可以到每个点,并且不影响真正更新结果,所以将边权定为\(d[0]-5\)

如果定为0,每一个点的d都会为0,会影响正确答案。

2.在SPFA初始添加操作时,除了初始化超级原点0,还要初始化起点。如果不初始化起点,d[1]=d[0]-5,而每个点被0更新后都是d[0]-5,则起点无法更新任何点。

添加超级原点,相当于让整张图有第二个起点,所以两个起点都要进行初始化。

#include<bits/stdc++.h>
using namespace std;

const int N=1e3+5,M=2e4+5;
int n,ml,md,te,tail[N],cnt[N],d[N];
bool vis[N];
struct e_
{
	int v,w,pre;
}e[M+N];

void add(int u,int v,int w)
{
	e[++te]=(e_){v,w,tail[u]};
	tail[u]=te;
}

bool SPFA()
{
	deque<int>q;
	q.push_back(0);
	q.push_back(1);

	d[1]=d[0]=0;
	cnt[1]=cnt[0]=1;
	while(q.size())
	{
		int u=q.front();
		q.pop_front();
		vis[u]=0;
		
		for(int i=tail[u];i;i=e[i].pre)
		{
			int v=e[i].v,w=e[i].w;
			
			if(d[v]>d[u]+w)
			{
				d[v]=d[u]+w;
				cnt[v]++;
				if(cnt[v]>n) return 0;
				if(!vis[v])
				{
					vis[v]=1;
					if(q.empty()||d[q.front()]<d[v]) q.push_back(v);
					else q.push_front(v);
				}
			}
		}	
	}
	return 1;
}

int main()
{
	scanf("%d %d %d",&n,&ml,&md);
	for(int i=1,u,v,w;i<=ml;++i)
	{
		scanf("%d %d %d",&u,&v,&w);
		add(u,v,w);
	}
	for(int i=1,u,v,w;i<=md;++i)
	{
		scanf("%d %d %d",&u,&v,&w);
		add(v,u,-w);
	}
	
	memset(d,0x3f,sizeof(d));
	
	for(int i=1;i<n;++i) add(i+1,i,0),add(0,i,d[0]-5);
	add(0,n,d[0]-5);
	
	int val=d[0]-5;
	
	if(!SPFA()) printf("-1");
 	else
	if(d[n]==val) printf("-2");
	else printf("%d",d[n]);
}

糖果

2011年省队选拔赛四川

时间限制: 1 s

空间限制: 128000 KB

题目描述 Description

幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候,lxhgww需要满足小朋友们的K个要求。幼儿园的糖果总是有限的,lxhgww想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。

输入描述 Input Description

输入的第一行是两个整数N,K。

接下来K行,表示这些点需要满足的关系,每行3个数字,X,A,B。

如果X=1, 表示第A个小朋友分到的糖果必须和第B个小朋友分到的糖果一样多;

如果X=2, 表示第A个小朋友分到的糖果必须少于第B个小朋友分到的糖果;

如果X=3, 表示第A个小朋友分到的糖果必须不少于第B个小朋友分到的糖果;

如果X=4, 表示第A个小朋友分到的糖果必须多于第B个小朋友分到的糖果;

如果X=5, 表示第A个小朋友分到的糖果必须不多于第B个小朋友分到的糖果;

输出描述 Output Description

输出一行,表示lxhgww老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出-1

样例输入 Sample Input

5 7

1 1 2

2 3 2

4 4 1

3 4 5

5 4 5

2 3 5

4 5 1

样例输出 Sample Output

11

数据范围及提示 Data Size & Hint

对于30%的数据,保证 N<=100

对于100%的数据,保证 N<=100000

对于所有的数据,保证 K<=100000,1<=X<=5,1<=A, B<=N

题解:

求最小值,所以关系为\(>=\),并求最长路。

\(1:d[A]-d[B]>=0,d[B]-d[A]>=0\)

\(2:d[A]-d[B]<0—>d[B]-d[A]>0—>d[B]-d[A]>=1\)

$3:d[A]-d[B]>=0 $

\(4:d[A]-d[B]>0—>d[A]-d[B]>=1\)

\(5:d[A]-d[B]<=0—>d[B]-d[A]>=0\)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+2;
int n,m,te,tail[N],cnt[N];
ll ans,d[N];
bool vis[N];
struct e_
{
	int v,w,pre;
}e[N*3];

inline void add(int u,int v,int w)
{
	e[++te]=(e_){v,w,tail[u]};
	tail[u]=te;
}

bool SPFA()
{
	deque<int>q;
	q.push_back(0);
	
	d[0]=0;
	cnt[0]=1;
	
	while(q.size())
	{
		int u=q.front();
		q.pop_front();
		vis[u]=0;
		
		for(int i=tail[u];i;i=e[i].pre)
		{
			int v=e[i].v,w=e[i].w;
			if(d[v]<(ll)d[u]+w)
			{
				d[v]=(ll)d[u]+w;
				cnt[v]++;
				if(cnt[v]>n) return 0;
				if(!vis[v])
				{
					vis[v]=1;
					if(q.empty()||d[q.front()]>d[v]) q.push_back(v);
					else q.push_front(v);
				}
			}
		}
	}
	return 1;
}

int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1,x,a,b;i<=m;++i)
	{
		scanf("%d %d %d",&x,&a,&b);
		switch(x)
		{
			case 1:{add(a,b,0);add(b,a,0);break;}
			case 2:{add(a,b,1);break;}
			case 3:{add(b,a,0);break;}
			case 4:{add(b,a,1);break;}
			case 5:{add(a,b,0);break;}
		}
	}
	for(int i=1;i<=n;++i) add(0,i,1);
	if(!SPFA()) printf("-1");
	else
	{
		for(int i=1;i<=n;++i) ans+=d[i];
		printf("%lld",ans);
	}
}
posted @ 2020-10-23 20:10  林生。  阅读(113)  评论(0)    收藏  举报