P3275 [SCOI2011]糖果

题目描述

幼儿园里有 \(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。 \)

输入输出样例

\(输入 #1\)

5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1

\(输出 #1\)

11

说明/提示
对于 \(30%\) 的数据,保证 \(N\leq100\)
对于 \(100%\) 的数据,保证 \(N\leq100000\)
对于所有的数据,保证 \(K\leq100000\), \(1\leq X\leq5\), \(1\leq A\), \(B\leq N\)

思路

首先这个题要用到差分约束。初学差分约束,应该要明确它的概念和它的用处。。。。。。。。。。。
那么回到这个题上,因为要使总糖果数尽量少,所以大于或者小于之间只差1个最优,而可以取等时当然取等最优,那么存图就搞定了。因为不一定是哪一个人手中的糖果最少,所以设立一个0号节点,并到每一个人的边权都是1(每一个人手里都至少有一个糖果)。因为要满足所有的条件,也就是只要加1这个1必须加,不然不符合题意,所以用SPFA(bfs)跑一遍单源最长路(从0号节点开始),就是每个人满足条件是的最少持有的糖果(最少持有体现在存图中的1和0),再将所有的最长路加起来即为最终答案。

代码

#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long int ll;
const int N=100005,M=300005;
ll tot[N],ver[M],Next[M],head[N],d[N],edge[M];
bool v[N];
ll ans,n,k,cnt;
queue q;
void add(ll x,ll y,ll z){
	ver[++cnt]=y;
	edge[cnt]=z;
	Next[cnt]=head[x];
	head[x]=cnt; 
} 
int main()
{
	scanf("%lld%lld",&n,&k);
	for(ll i(1),op,u,v;i<=k;++i){
		scanf("%lld%lld%lld",&op,&u,&v);
		if(op==1){//u=v 
			add(u,v,0);
			add(v,u,0);//糖果数相等,那么相差0,所以边权为0 
		}
		else if(op==2){//v>u
			if(u==v){
				printf("-1\n");//同一个人的糖果数肯定相等,所以如果一个大一个小肯定不对,直接输出不行 
				return 0;
			}
			add(u,v,1);//贪心思想,要使糖果数最少,v比u多一个糖果才满足题意 
		}
		else if(op==3){//u<=v
			add(v,u,0);//大于等于和小于等于都取等才符合贪心思想 
		}
		else if(op==4){//u>v
			if(u==v){
				printf("-1\n");
				return 0;
			}
			add(v,u,1);
		}
		else if(op==5){//v<=u
			add(u,v,0);
		}
	}
	for(ll i=n;i>=1;i--){
		add(0,i,1);//初始一个0节点,因为不一定哪一个人糖果最少,所以不一定从哪个人开始传递关系。而每个人手里都至少有一个糖果,所以相差1 
	} 
	v[0]=1;
	q.push(0);
	while(!q.empty()){//SPFA
		ll x=q.front();
		q.pop();
		if(tot[x]==n-1){//判定环,因为如果有环的话说明大小关系出现了矛盾,而SPFA判断环的方法就是看是否入队了n-1次 
			printf("-1\n");//有环那么不行 
			return 0;
		}
		v[x]=0;
		tot[x]++;//入队次数 
		for(ll i=head[x];i;i=Next[i]){
			ll y=ver[i],z=edge[i];
			if(d[y]

但是,请注意,由于SPFA(bfs)的时间复杂度最坏是O(nm),这个题数据范围较大,按理来说会TLE。中间有一个玄学操作,就是我在存0号节点的时候,是倒着循环的,我也不知道为什么,或许是存边顺序会影响SPFA的时间复杂度。管他呢,反正这题正解不是差分约束。。。就当做一个板子题吧。

你可能感兴趣的:(P3275 [SCOI2011]糖果)