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

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的松弛操作的式子里就可以了。

  注意最后建边的时候要倒着建一遍,hzwer学长说有一个点是10w的点穿成的一条链所以正着会TLE。

  还有就是数据有自环什么的我试着删掉了自环判断发现也能过就是跑的慢了一(hao)点(duo)。

  284ms:(有自环判断)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN=100001;
struct xx
{
	int from,to,nxt,w;
}e[MAXN<<2];
int a[MAXN],cnt,dist[MAXN],n,m,head[MAXN];
int check[MAXN];
bool visit[MAXN];
queue <int > Q;
inline void add(int x,int y,int z)
{
	cnt++;
	e[cnt].from=x;
	e[cnt].to=y;
	e[cnt].w=z;
	e[cnt].nxt=head[x];
	head[x]=cnt;
}
bool SPFA()
{
	int i,t;
	visit[0]=1;
	Q.push(0);
	while(!Q.empty())
	{
		t=Q.front();
		Q.pop();
		visit[t]=0;
		for(i=head[t];i;i=e[i].nxt)
		{
			if(dist[t]+e[i].w>dist[e[i].to])
			{
				dist[e[i].to]=dist[t]+e[i].w;
				if(++check[e[i].to]>n) return false;
				if(!visit[e[i].to]) 
				{
					visit[e[i].to]=1;
					Q.push(e[i].to);
				}
			}
		}
	}
	return true;
}
int main(int argc, char *argv[])
{
	int i,j,x,y,z,op;
	long long ans=0;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&op,&x,&y);
		if(op==1) add(x,y,0),add(y,x,0);
		else if(op==2) 
		{
			if(x==y) 
			{
				puts("-1");
				return 0;
			} 
			add(x,y,1);
		}
		else if(op==3) add(y,x,0);
		else if(op==4)
		{
			if(x==y) 
			{
				puts("-1");
				return 0;
			}
			add(y,x,1);
		} 
		else if(op==5) add(x,y,0);
	}
	for(i=n;i>0;i--) add(0,i,1);
	if(!SPFA()) 
	{
		puts("-1");
		return 0;
	}
	for(i=1;i<=n;i++) ans+=dist[i];
	printf("%lld\n",ans);
	return 0;
}

6004ms:(未加自环判断)

 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN=100001;
struct xx
{
	int from,to,nxt,w;
}e[MAXN<<2];
int a[MAXN],cnt,dist[MAXN],n,m,head[MAXN];
int check[MAXN];
bool visit[MAXN];
queue <int > Q;
inline void add(int x,int y,int z)
{
	cnt++;
	e[cnt].from=x;
	e[cnt].to=y;
	e[cnt].w=z;
	e[cnt].nxt=head[x];
	head[x]=cnt;
}
bool SPFA()
{
	int i,t;
	visit[0]=1;
	Q.push(0);
	while(!Q.empty())
	{
		t=Q.front();
		Q.pop();
		visit[t]=0;
		for(i=head[t];i;i=e[i].nxt)
		{
			if(dist[t]+e[i].w>dist[e[i].to])
			{
				dist[e[i].to]=dist[t]+e[i].w;
				if(++check[e[i].to]>n) return false;
				if(!visit[e[i].to]) 
				{
					visit[e[i].to]=1;
					Q.push(e[i].to);
				}
			}
		}
	}
	return true;
}
int main(int argc, char *argv[])
{
	int i,j,x,y,z,op;
	long long ans=0;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&op,&x,&y);
		if(op==1) add(x,y,0),add(y,x,0);
		else if(op==2) add(x,y,1);
		else if(op==3) add(y,x,0);
		else if(op==4) add(y,x,1);
		else if(op==5) add(x,y,0);
	}
	for(i=n;i>0;i--) add(0,i,1);
	if(!SPFA()) 
	{
		puts("-1");
		return 0;
	}
	for(i=1;i<=n;i++) ans+=dist[i];
	printf("%lld\n",ans);
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章