洛谷 P3275 [SCOI2011]糖果

题目链接

题解

差分约束 学过的应该都会做
不会的自行百度,这里不多讲

opt=1 连一条长度为0的双向边
opt=2 (u->v) \(len=-1\)
opt=3 (v->u) \(len=0\)
opt=4 (v->u) \(len=-1\)
opt=5 (u->v) \(len=0\)

0到其他点都连一条长度为-1的边(从n到1连玄学的力量, 正着加边会T)
然后spfa最短路即可

Code

#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std;

inline int gi() {
    int f = 1, s = 0;
    char c = getchar();
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    if (c == '-') f = -1, c = getchar();
    while (c >= '0' && c <= '9') s = s*10+c-'0', c = getchar();
    return f == 1 ? s : -s;
}
const int N = 100010;
struct node {
	int to, next, w;	
}g[(N<<1)+N];
int last[N], gl;
inline void add(int x, int y, int z) {
	g[++gl] = (node) {y, last[x], z};
	last[x] = gl;
	return ;
}
LL dis[N];
bool vis[N];
int cnt[N];
queue<int> q;
int main() {
	int n = gi(), k = gi();
	for (int i = 1; i <= k; i++) {
		int k = gi(), u = gi(), v = gi();
		if (k == 1)
			add(u, v, 0), add(v, u, 0);
		else if (k == 2) {
			if (u == v) {
				puts("-1");
				return 0;
			}
			add(u, v, -1);
		}
		else if (k == 3) add(v, u, 0);
		else if (k == 4) {
			if (u == v) {
				puts("-1");
				return 0;
			}
			add(v, u, -1);
		}
		else add(u, v, 0);
	}
	for (int i = n; i >= 1; i--) add(0, i, -1);
	q.push(0);
	memset(dis, 127/3, sizeof(dis));
	dis[0] = 0;
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		if (++cnt[u] == n) {
			puts("-1");
			return 0;
		}
		for (int i = last[u]; i; i = g[i].next) {
			int v = g[i].to;
			if (dis[v] > dis[u]+g[i].w) {
				dis[v] = dis[u]+g[i].w;
				if (!vis[v]) q.push(v), vis[v] = 1;
			}
		}
		vis[u] = 0;
	}
	LL ans = 0;
	for (int i = 1; i <= n; i++)
		ans += dis[i];
	printf("%lld\n", -ans);
    return 0;
}

posted @ 2018-11-01 16:57  zzy2005  阅读(94)  评论(0编辑  收藏  举报