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 }

 

posted @ 2018-09-24 23:46  _努力努力再努力x  阅读(312)  评论(0编辑  收藏  举报