BZOJ2330: [SCOI2011]糖果

2330: [SCOI2011]糖果

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 6692  Solved: 2226
[Submit][Status][Discuss]

Description

 

幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候,lxhgww需要满足小朋友们的K个要求。幼儿园的糖果总是有限的,lxhgww想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。

 

Input

输入的第一行是两个整数NK

接下来K行,表示这些点需要满足的关系,每行3个数字,XAB

如果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

5 7

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

 

【题解】

差分约束。

超级源点向所有边连一条权为1的边,表示至少要有一个糖果。

做最长路,求最小值。

具体见

[研究]最短路、最长路与差分约束的最大解、最小解

会卡SPFA,倒序从超级源点加边

网上有一个放SPFA被卡的方法:给每个点rand一个值,按值取

 

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <queue>
  6 #include <vector> 
  7 #define max(a, b) ((a) > (b) ? (a) : (b))
  8 #define min(a, b) ((a) < (b) ? (a) : (b))
  9 
 10 inline void read(int &x)
 11 {
 12     x = 0;char ch = getchar(), c = ch;
 13     while(ch < '0' || ch > '9')c = ch, ch = getchar();
 14     while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();
 15     if(c == '-')x = -x;
 16 }
 17 
 18 const int INF = 0x3f3f3f3f;
 19 const int MAXN = 200000 + 10;
 20 const int MAXM = 200000 + 10;
 21 
 22 struct Edge
 23 {
 24     int u,v,w,next;
 25     Edge(int _u, int _v, int _w, int _next){u = _u;v = _v;w = _w;next = _next;}
 26     Edge(){}
 27 }edge[MAXM << 1];
 28 
 29 int n,m,head[MAXN],cnt;
 30 
 31 inline void insert(int a, int b, int c)
 32 {
 33     edge[++cnt] = Edge(a, b, c, head[a]);
 34     head[a] = cnt;
 35 }
 36 
 37 std::queue<int> q;
 38 int b[MAXN], d[MAXN], cntt[MAXN];
 39 
 40 inline int SPFA()
 41 {
 42     memset(cntt, 0, sizeof(cntt));
 43     memset(b, 0, sizeof(b));
 44     memset(d, -1, sizeof(d));
 45     b[0] = 1, d[0] = 0;
 46     q.push(0);++cntt[0];
 47     while(q.size())
 48     {
 49         int now = q.front();q.pop();
 50         b[now] = 0;
 51         for(register int pos = head[now];pos;pos = edge[pos].next)
 52         {
 53             int v = edge[pos].v;
 54             if(d[now] + edge[pos].w > d[v])
 55             {
 56                 d[v] = d[now] + edge[pos].w;
 57                 if(!b[v]) 
 58                 {
 59                     q.push(v), ++ cntt[v]; 
 60                     if(cntt[v] >= n) return 0;
 61                 }
 62             }
 63         }
 64     }
 65     return 1;
 66 }
 67 
 68 int main()
 69 {
 70     read(n), read(m);
 71     register int tmp1, tmp2, tmp3;
 72     for(register int i = 1;i <= m;++ i)
 73     {
 74         read(tmp1), read(tmp2), read(tmp3);
 75         if(tmp1 == 1)
 76         {
 77             insert(tmp2, tmp3, 0);
 78             insert(tmp3, tmp2, 0);
 79         }
 80         else if(tmp1 == 2)
 81         {
 82             if(tmp3 == tmp2)
 83             {
 84                 printf("-1");return 0;
 85             }
 86             else insert(tmp2, tmp3, 1);
 87         }
 88         else if(tmp1 == 3)
 89             insert(tmp3, tmp2, 0);
 90         else if(tmp1 == 4)
 91         {
 92             if(tmp2 == tmp3)
 93             {
 94                 printf("-1");return 0;
 95             }
 96             else insert(tmp3, tmp2, 1);
 97         }
 98         else if(tmp1 == 5)
 99             insert(tmp2, tmp3, 0);    
100     }
101     for(register int i = n;i >= 1;-- i) insert(0, i, 1);
102     if(SPFA())
103     {
104         long long ans = 0;
105         for(register int i = 0;i <= n;++ i)
106             ans += d[i];
107         printf("%lld", ans);
108     }
109     else
110         printf("-1");
111     return 0;
112 }
BZOJ2330

 

posted @ 2017-09-20 15:00  嘒彼小星  阅读(187)  评论(0编辑  收藏  举报