bzoj 2330: [SCOI2011]糖果
2330: [SCOI2011]糖果
Description
幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候,lxhgww需要满足小朋友们的K个要求。幼儿园的糖果总是有限的,lxhgww想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。
Input
输入的第一行是两个整数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
输出一行,表示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
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1
Sample Output
11
HINT
【数据范围】
对于30%的数据,保证 N<=100
对于100%的数据,保证 N<=100000
对于所有的数据,保证 K<=100000,1<=X<=5,1<=A, B<=N
题解:
很裸的差分约束,就是条件多了一些。。
题目说要求老师至少需要准备的糖果数,即需要每个人的糖果数尽量少,我们按x+z<=y建x到y的边,长度为z,然后求最长路。
注意判环以及建一个超级源点。
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; int i,n,m,x,y,z,t,p[100005],g[100005],r[100005]; int tot,head[100005],Next[400005],to[400005],v[400005]; long long ans,dis[100005]; void add(int x,int y,int z) { tot++; to[tot]=y; v[tot]=z; Next[tot]=head[x]; head[x]=tot; } int main() { scanf("%d%d",&n,&m); for(i=0;i<=n;i++) head[i]=-1; for(i=1;i<=m;i++) { scanf("%d%d%d",&z,&x,&y); if(z==1) { add(x,y,0); add(y,x,0); } else if(z==2) { if(x==y) {printf("-1");return 0;} add(x,y,1); } else if(z==3) add(y,x,0);else if(z==4) { if(x==y) {printf("-1");return 0;} add(y,x,1); } else if(z==5) add(x,y,0); } for(i=1;i<=n;i++) add(0,i,1); dis[0]=0; t=1;g[1]=0;p[0]=1; r[0]=1; while(t) { x=g[t]; t--; p[x]=0; for(i=head[x];i!=-1;i=Next[i]) if(dis[x]+v[i]>dis[to[i]]) { dis[to[i]]=dis[x]+v[i]; if(p[to[i]]==0) { r[to[i]]++; if(r[to[i]]>n) {printf("-1");return 0;} p[to[i]]=1; t++; g[t]=to[i]; } } } ans=0; for(i=1;i<=n;i++) ans+=dis[i]; cout<<ans; return 0; }
一念起,天涯咫尺; 一念灭,咫尺天涯。