[bzoj2330][SCOI2011]糖果

题目大意:要求给 $n$ 个人分配糖果,记第 $i$ 个人分配到的糖果数为 $S_i$,要求 $S_i > 0$。另外有 $k$ 个限制,每个限制形如 $X A B(X \in [1,5])$,分别表示:

$X=1,S_A = S_B$

$X=2,S_A < S_B$

$X=3,S_A \geq S_B$

$X=4,S_A > S_B$

$X=5,S_A \leq S_B$

求至少需要多少糖果?

题解:差分约束。

对于差分不等式,$a − b \leq c$,建一条 $b$ 到 $a$ 的权为 $c$ 的边,求的是最短路,得到的是最大值,负环表示无解。

对于差分不等式,$a − b \geq c$,建一条 $b$ 到 $a$ 的权为 $c$ 的边,求的是最长路,得到的是最小值,正环表示无解。

因为求的是最小值,将不等式转化为 $a − b \geq c$ 的形式求最长路即可。注意判自环。

卡点:1.最开始从$0$向各个点连一条权值为$1$的边来跑,$TLE+WA$,改成每个点跑一遍就$AC$了

 

C++ Code:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#define maxn 100010
using namespace std;
const long long inf = 9223372036854775807;
int n, k, x, a, b;

int head[maxn], cnt;
struct Edge {
	int to, nxt, w;
} e[maxn << 1];
void add(int a, int b, int c) {
	e[++cnt] = (Edge) {b, head[a], c}; head[a] = cnt;
}

long long d[maxn];
int num[maxn];
bool vis[maxn];
queue <int> q;
void spfa(int rt) {
	q.push(rt);
	while (!q.empty()) {
		int u = q.front(); q.pop();
		vis[u] = false;
		for (int i = head[u]; i; i = e[i].nxt) {
			int v = e[i].to;
			if (d[v] < d[u] + e[i].w) {
				d[v] = d[u] + e[i].w;
				num[v]++;
				if (num[v] >= n) {
					puts("-1");
					exit(0);
				}
				if (!vis[v]) {
					vis[v] = true;
					q.push(v);
				}
			}
		}
	}
}
int main() {
	scanf("%d%d", &n, &k);
	for (int i = 0; i < k; i++) {
		scanf("%d%d%d", &x, &a, &b);
		switch (x) {
			case 1: {
				add(a, b, 0);
				add(b, a, 0);
				break;
			}
			case 2: {
				if (a == b) {
					puts("-1");
					return 0;
				}
				add(a, b, 1);
				break;
			}
			case 3: {
				add(b, a, 0);
				break;
			}
			case 4: {
				if (a == b) {
					puts("-1");
					return 0;
				}
				add(b, a, 1);
				break;
			}
			default: add(a, b, 0);
		}
	}
	for (int i = 1; i <= n; i++) d[i] = 1;
	for (int i = 1; i <= n; i++) {
		spfa(i);
	}
	long long ans = 0;
	for (int i = 1; i <= n; i++) ans += d[i];
	printf("%lld\n", ans);
	return 0;
} 

  

posted @ 2018-08-18 19:03  Memory_of_winter  阅读(161)  评论(0编辑  收藏  举报