bzoj2330 [SCOI2011]糖果
2330: [SCOI2011]糖果
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 6415 Solved: 2120
[Submit][Status][Discuss]
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
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
Source
分析:比较明显的一道差分约束系统的题,这类题一般是这样的:如果要求差值最大,那么转换成小于等于号的式子,然后求最短路,如果要求差值最小,那么转换成大于等于号,求最长路.
1: A == B,那么A >= B, B >= A,分别连边(A,B,0)、(B,A,0).
2: A < B等价于A <= B-1,连边(A,B,1).
3: A >= B,连边(B,A,0).
4: A > B等价于B <= A - 1,连边(B,A,1).
5: A <= B,连边(A,B,0).
然后跑一下spfa判一下负环就能过了.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <queue> using namespace std; int n,k; int head[100010],to[200010],nextt[200010],w[200010],tot,cnt[100010]; long long ans,d[100010]; bool vis[100010]; void add(int x,int y,int z) { w[tot] = z; to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } bool spfa() { queue <int> q; for (int i = 1; i <= n; i++) { d[i] = 1; vis[i] = true; q.push(i); } while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for (int i = head[u]; i + 1; i = nextt[i]) { int v = to[i]; if (d[v] < d[u] + w[i]) { d[v] = d[u] + w[i]; if (!vis[v]) { ++cnt[v]; if (cnt[v] >= n) return false; vis[v] = 1; q.push(v); } } } } return true; } int main() { memset(head,-1,sizeof(head)); scanf("%d%d",&n,&k); for (int i = 1; i <= k; i++) { int x,a,b; scanf("%d%d%d",&x,&a,&b); if (x == 1) { add(a,b,0); add(b,a,0); } if (x == 2) { add(a,b,1); } if (x == 3) { add(b,a,0); } if (x == 4) { add(b,a,1); } if (x == 5) { add(a,b,0); } } if (!spfa()) printf("-1\n"); else { for (int i = 1; i <= n; i++) ans += d[i]; printf("%lld\n",ans); } return 0; }