BZOJ 2330: [SCOI2011]糖果
2330: [SCOI2011]糖果
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 4523 Solved: 1405
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
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
差分约束系统。将不等关系转化成图上的边关系,然后跑最短路/最长路就可以得到满足不等关系的最优解。(思路有些像2-sat呢)
1 /**/ 2 #include<iostream> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstring> 6 #include<algorithm> 7 #include<queue> 8 using namespace std; 9 const int mxn=200000; 10 int n,m,k; 11 struct edge{ 12 int v,dis; 13 int next; 14 }e[450000]; 15 int hd[mxn],cnt; 16 int dis[mxn]; 17 bool inq[mxn]; 18 int vis[mxn];//到达次数 19 void add_edge(int x,int y,int dis){ 20 e[++cnt].next=hd[x];e[cnt].v=y;e[cnt].dis=dis;hd[x]=cnt; 21 } 22 bool SPFA(){ 23 queue<int>q; 24 q.push(0); 25 inq[0]=1; 26 vis[0]=1; 27 while(!q.empty()){ 28 int u=q.front(); 29 for(int i=hd[u];i;i=e[i].next){ 30 int v=e[i].v; 31 if(dis[u]+e[i].dis>dis[v]){ 32 dis[v]=dis[u]+e[i].dis; 33 if(++vis[v]>=n)return 0; 34 if(!inq[v]){ 35 q.push(v); 36 inq[v]=1; 37 } 38 } 39 } 40 q.pop(); 41 inq[u]=0; 42 } 43 return 1; 44 } 45 int main(){ 46 scanf("%d%d",&n,&k); 47 int x,a,b; 48 int i,j; 49 for(i=1;i<=k;i++){ 50 scanf("%d%d%d",&x,&a,&b); 51 switch(x){ 52 case 1:{ 53 add_edge(a,b,0); 54 add_edge(b,a,0);break; 55 } 56 case 2:{ 57 if(a==b){printf("-1\n");return 0;} 58 add_edge(a,b,1);break; 59 } 60 case 3:{ 61 add_edge(b,a,0); 62 break; 63 } 64 case 4:{ 65 if(a==b){printf("-1\n");return 0;} 66 add_edge(b,a,1); 67 break; 68 } 69 case 5:{ 70 add_edge(a,b,0); 71 break; 72 } 73 } 74 } 75 for(i=n;i;i--)add_edge(0,i,1);//每个小朋友至少有一块糖 76 if(!SPFA()){printf("-1\n");return 0;} 77 long long ans=0; 78 for(i=1;i<=n;i++)ans+=dis[i]; 79 printf("%lld\n",ans); 80 return 0; 81 }
本文为博主原创文章,转载请注明出处。