差分约束问题
差分约束问题



区间
给定 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_超级原点
为了防止存在多个连通块,并且存在负环的联通块与节点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);
}
}

浙公网安备 33010602011771号