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;
}