BZOJ 2330 糖果 差分约束求最小值
题目链接:
https://www.lydsy.com/JudgeOnline/problem.php?id=2330
题目大意:
幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候,lxhgww需要满足小朋友们的K个要求。幼儿园的糖果总是有限的,lxhgww想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。
输入的第一行是两个整数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个小朋友分到的糖果;
输出一行,表示lxhgww老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出-1。
思路:
差分约束系统求最小值,要用最长路。
差分约束系统求最大值时,构造边按照:d[v] - d[u] <= Edge[u][v] (u->v连边),求解时按照最短路求解(也就是松弛的时候按照原来的方式进行松弛)
求最小值时,构造边按照:d[v] - d[u] >= Edge[u][v](u->v连边),求解时按照最长路进行求解(松弛的时候和原来相反)
坑:
添加边的时候需要逆序添加,数据原因。(也可以将要添加的边存起来,随机一下添加)
需要特判自环的情况不然也会T
1 #include<bits/stdc++.h> 2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf 3 #define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时 4 #define Min(a, b) ((a) < (b) ? (a) : (b)) 5 #define Mem(a) memset(a, 0, sizeof(a)) 6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1)) 7 #define MID(l, r) ((l) + ((r) - (l)) / 2) 8 #define lson ((o)<<1) 9 #define rson ((o)<<1|1) 10 #define Accepted 0 11 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} 17 while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 typedef long long ll; 21 const int maxn = 1000000 + 10; 22 const int MOD = 1000000007;//const引用更快,宏定义也更快 23 const ll INF = 1e12 + 7; 24 const double eps = 1e-6; 25 26 struct edge 27 { 28 ll u, v; 29 ll w; 30 ll next; 31 }; 32 edge a[maxn]; 33 ll head[maxn], node; 34 void addedge(ll u, ll v, ll w) 35 { 36 a[node].u = u; 37 a[node].v = v; 38 a[node].w = w; 39 a[node].next = head[u]; 40 head[u] = node++; 41 } 42 43 ll cnt[maxn]; 44 bool vis[maxn]; 45 ll d[maxn]; 46 ll n; 47 bool SPFA(ll u) 48 { 49 queue<ll>q; 50 memset(vis, 0, sizeof(vis)); 51 memset(cnt, 0, sizeof(cnt)); 52 for(int i = 1; i <= n; i++)d[i] = -INF;//赋值成最小值 来求解最长路 53 d[u] = 0; 54 vis[u] = 1; 55 q.push(u); 56 while(!q.empty()) 57 { 58 ll u = q.front(); 59 q.pop(); 60 vis[u] = 0; 61 for(ll i = head[u]; i != -1; i = a[i].next) 62 { 63 edge& e = a[i]; 64 if(d[e.v] < d[u] + e.w)//求最长路松弛符号改变 65 { 66 d[e.v] = d[u] + e.w; 67 if(!vis[e.v]) 68 { 69 q.push(e.v); 70 vis[e.v] = 1; 71 if(++cnt[e.v] >= n)return false; 72 } 73 } 74 } 75 } 76 return true; 77 } 78 int main() 79 { 80 memset(head, -1, sizeof(head)); 81 ll k, x, a, b; 82 scanf("%lld%lld", &n, &k); 83 for(ll i = n; i >= 1; i--)addedge(0, i, 0); 84 bool flag = 0; 85 while(k--) 86 { 87 scanf("%lld%lld%lld", &x, &a, &b); 88 if(x == 1) 89 { 90 addedge(a, b, 0); 91 addedge(b, a, 0); 92 } 93 else if(x == 2) 94 { 95 if(a == b)flag = 1; 96 addedge(a, b, 1); 97 } 98 else if(x == 3) 99 { 100 addedge(b, a, 0); 101 } 102 else if(x == 4) 103 { 104 if(a == b)flag = 1; 105 addedge(b, a, 1); 106 } 107 else 108 { 109 addedge(a, b, 0); 110 } 111 } 112 if(!flag && SPFA(0)) 113 { 114 ll ans = 0; 115 for(ll i = 1; i <= n; i++)ans += d[i] + 1;//加上最开始的1 116 printf("%lld\n", ans); 117 } 118 else 119 { 120 printf("-1\n"); 121 } 122 return Accepted; 123 }