BZOJ2330:[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
Solution
差分约束……好像题不是很多的样子
若要求最小值,则将式子化为X-Y>=K,连(Y,X,K),求最长路
若要求最大值,则将式子化为X-Y<=K,连(Y,X,K),求最短路
这个题可能会炸longlong
SPFA会被卡所以0点向别的点连边时要倒着连
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<queue> 5 #define N (200000+100) 6 using namespace std; 7 struct node 8 { 9 int len,next,to; 10 } edge[N*2]; 11 int head[N],num_edge; 12 int cnt[N],n,m; 13 long long dis[N],ans; 14 bool used[N]; 15 queue<int>q; 16 17 void add(int u,int v,int l) 18 { 19 edge[++num_edge].to=v; 20 edge[num_edge].next=head[u]; 21 edge[num_edge].len=l; 22 head[u]=num_edge; 23 } 24 25 bool Spfa() 26 { 27 memset(dis,-0x3f,sizeof(dis)); 28 q.push(0); 29 dis[0]=0; 30 used[0]=true; 31 while (!q.empty()) 32 { 33 int x=q.front(); 34 q.pop(); 35 for (int i=head[x]; i!=0; i=edge[i].next) 36 if (dis[x]+edge[i].len>dis[edge[i].to]) 37 { 38 dis[edge[i].to]=dis[x]+edge[i].len; 39 if (!used[edge[i].to]) 40 { 41 q.push(edge[i].to); 42 cnt[edge[i].to]++; 43 if (cnt[edge[i].to]>=n) return false; 44 used[edge[i].to]=true; 45 } 46 } 47 used[x]=false; 48 } 49 for (int i=1; i<=n; ++i) 50 ans+=dis[i]; 51 return ans; 52 } 53 54 int main() 55 { 56 int opt,x,y; 57 scanf("%d%d",&n,&m); 58 for (int i=1; i<=m; ++i) 59 { 60 scanf("%d%d%d",&opt,&x,&y); 61 if (opt==1) add(x,y,0), add(y,x,0); 62 if (opt==2) 63 { 64 if (x==y)//记得加上特判 65 { 66 printf("-1"); 67 return 0; 68 } 69 add(x,y,1); 70 } 71 if (opt==3) add(y,x,0); 72 if (opt==4) 73 { 74 if (x==y)//记得加上特判 75 { 76 printf("-1"); 77 return 0; 78 } 79 add(y,x,1); 80 } 81 if (opt==5) add(x,y,0); 82 } 83 for (int i=n; i>=1; --i) add(0,i,1); 84 if (!Spfa()) printf("-1"); 85 else printf("%lld",ans); 86 }