【BZOJ2330】【SCOI2011】糖果 [差分约束]

2330: [SCOI2011]糖果

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

Description

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

Input

  输入的第一行是两个整数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个小朋友分到的糖果;

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

Main idea

  有若干个小朋友分糖果,要求每个人至少分到一颗糖,给出若干个数之间大小或者等于的限制,求最少需要多少个糖果可以满足条件。

Solution

  发现有若干限制大小,那么我们想到了差分约束系统,在两点之间连一条带权边,根据限制条件决定边权。因为要满足所有情况,我们先将所有点入队,跑一遍最长路即可求出答案。

Code

 1 #include<iostream>  
 2 #include<algorithm>  
 3 #include<cstdio>  
 4 #include<cstring>  
 5 #include<cstdlib>  
 6 #include<cmath>  
 7 using namespace std;  
 8     
 9 const int ONE=200001;
10 const int INF=2147483640;
11 
12 int n,m;
13 int PD,x,y;
14 int next[ONE],first[ONE],go[ONE],tot;
15 int w[ONE];
16 int dist[100001];
17 int vis[100001],q[1000001],tou,wei;
18 long long Ans;
19 int Take_ring[100001];
20 
21 int get()
22 { 
23         int res,Q=1;    char c;
24         while( (c=getchar())<48 || c>57)
25         if(c=='-')Q=-1;
26         if(Q) res=c-48; 
27         while((c=getchar())>=48 && c<=57) 
28         res=res*10+c-48; 
29         return res*Q; 
30 }
31 
32 int Add(int u,int v,int z)
33 {
34         next[++tot]=first[u];    first[u]=tot;    go[tot]=v;    w[tot]=z;
35 }
36 
37 void PD_same(int x,int y)
38 {
39         if(x==y)
40         {
41             printf("-1");
42             exit(0);
43         }
44 }
45 
46 int Spfa()
47 {
48         while(tou<wei)
49         {
50             int u=q[++tou];
51             for(int e=first[u];e;e=next[e])
52             {
53                 int v=go[e];
54                 if(dist[v]<dist[u]+w[e])
55                 {
56                     if(++Take_ring[v]>=n) return 0;
57                     dist[v]=dist[u]+w[e];
58                     if(!vis[v])
59                     {
60                         vis[v]=1;
61                         q[++wei]=v;
62                     }
63                 }
64             }
65             vis[u]=0;
66         }
67         return 1;
68 }
69 
70 int main()
71 {
72         n=get();    m=get();
73         for(int i=1;i<=m;i++)
74         {
75             PD=get();    x=get();    y=get();
76             if(PD==1) Add(x,y,0),Add(y,x,0);
77             if(PD==2) Add(x,y,1),PD_same(x,y); 
78             if(PD==3) Add(y,x,0);
79             if(PD==4) Add(y,x,1),PD_same(x,y);
80             if(PD==5) Add(x,y,0);
81         } 
82         
83         for(int i=1;i<=n;i++)
84         {
85             dist[i]=vis[i]=1;
86             q[++wei]=i;
87         }
88         
89         if(!Spfa())
90         {
91             printf("-1");
92             return 0;
93         }
94         for(int i=1;i<=n;i++)
95         Ans+=(long long)dist[i];
96         printf("%lld",Ans);
97         
98 }
View Code

 

posted @ 2017-02-25 10:37  BearChild  阅读(215)  评论(0编辑  收藏  举报