1169. 糖果

题目链接

1169. 糖果

幼儿园里有 \(N\) 个小朋友,老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。

但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候, 老师需要满足小朋友们的 \(K\) 个要求。

幼儿园的糖果总是有限的,老师想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。

输入格式

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

小朋友编号从 \(1\)\(N\)

输出格式

输出一行,表示老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出 \(-1\)

数据范围

\(1 \le N < 10^5\),
\(1 \le K \le 10^5\),
\(1 \le X \le 5\),
\(1 \le A,B \le N\),
输入数据完全随机。

输入样例:

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

输出样例:

11

解题思路

差分约束

差分约束用来解决类似多个 \(x_i\leq x_{i+1}+c_i\) 这样的不等式的可行解或最优解的问题,而 \(x_i\leq x_{i+1}+c_i\) 正好对应求解最终最短路的形式,即求解最短路时,最终会有 \(x_i\leq c_1+c_2\dots +c_k\) 的形式,即在所有的下界中取最小值,此时取得的 \(x_i\) 为最大值,否则如果出现负环的话,即最终会循环到某个点,会产生矛盾,此时无解,同理,求解最长路对应求解每个 \(x_i\) 的最小值,当出现正环时无解。另外,由于给出的关系可能都为相对关系,而求解的往往需要绝对关系,可以建立一个虚拟源点 \(x_0\),即 \(d[x_0]=0\),将该点添加到其他关系中连边

本题求解最小值,故求最长路,且要求所有 \(x_i\geq 1\),即 \(x_i\geq x_0+1\),将 \(0\)\(1\) 之间连一条边权为 \(1\) 的边即可,其他建边同理,最后求一遍 \(spfa\) 即可

  • 时间复杂度:\(O(kn)\)

代码

// Problem: 糖果
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1171/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1e5+5;
int n,k,x;
int d[N],cnt[N];
int h[N],e[N*3],w[N*3],ne[N*3],idx;
bool v[N];
void add(int a,int b,int c)
{
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;	
}
bool spfa()
{
	stack<int> stk;
	stk.push(0);
	v[0]=true;
	memset(d,-0x3f,sizeof d);
	d[0]=0;
	while(stk.size())
	{
		int x=stk.top();
		stk.pop();
		v[x]=false;
		for(int i=h[x];~i;i=ne[i])
		{
			int y=e[i],ww=w[i];
			if(d[y]<d[x]+ww)
			{
				d[y]=d[x]+ww;
				cnt[y]=cnt[x]+1;
				if(cnt[y]>=n+1)return false;
				if(!v[y])stk.push(y),v[y]=true;
			}
		}
	}
	return true;
}
int main()
{
    scanf("%d%d",&n,&k);
    memset(h,-1,sizeof h);
	while(k--)
	{
		int a,b;
		scanf("%d%d%d",&x,&a,&b);
		if(x==1)add(a,b,0),add(b,a,0);
		else if(x==2)add(a,b,1);
		else if(x==3)add(b,a,0);
		else if(x==4)add(b,a,1);
		else
			add(a,b,0);
	}
	for(int i=1;i<=n;i++)add(0,i,1);
	if(!spfa())puts("-1");
	else
	{
		LL res=0;
		for(int i=1;i<=n;i++)res+=d[i];
		printf("%lld",res);
	}
    return 0;
}
posted @ 2022-08-12 16:02  zyy2001  阅读(21)  评论(0编辑  收藏  举报