题目大意:
N个人要分糖果,要求每个小朋友都要分到糖果,且要满足
K
K
K个要求,
对于每个要求给出一组
X
,
A
,
B
X,A,B
X,A,B:
X
=
1
X=1
X=1, 表示第
A
A
A个小朋友分到的糖果必须和第
B
B
B个小朋友分到的糖果一样多;
X
=
2
X=2
X=2, 表示第
A
A
A个小朋友分到的糖果必须少于第
B
B
B个小朋友分到的糖果;
X
=
3
X=3
X=3, 表示第
A
A
A个小朋友分到的糖果必须不少于第
B
B
B个小朋友分到的糖果;
X
=
4
X=4
X=4, 表示第
A
A
A个小朋友分到的糖果必须多于第
B
B
B个小朋友分到的糖果;
X
=
5
X=5
X=5, 表示第
A
A
A个小朋友分到的糖果必须不多于第
B
B
B个小朋友分到的糖果;
问至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。
K < = 100000 , 1 < = X < = 5 , 1 < = A , B < = N K<=100000,1<=X<=5,1<=A, B<=N K<=100000,1<=X<=5,1<=A,B<=N
分析:
明细的差分约束系统,
①A必须和B分的一样多
连边
A
−
>
B
,
B
−
>
A
,
边
权
为
0
A->B,B->A,边权为0
A−>B,B−>A,边权为0,即
A
A
A分的必须等于
B
B
B分的
②A分的必须少于B的个
连边
A
−
>
B
,
边
权
为
1
A->B,边权为1
A−>B,边权为1,即
B
B
B分的至少为
A
A
A分的
+
1
+1
+1
③A分的必须不少于B分的
连边
B
−
>
A
,
边
权
为
0
B->A,边权为0
B−>A,边权为0,即
A
A
A分的至少等于
B
B
B分的
④A分的必须多于B分的
连边
B
−
>
A
,
边
权
为
1
B->A,边权为1
B−>A,边权为1,即
A
A
A分的至少为
B
B
B分的
+
1
+1
+1
⑤A分的必须不多于B分的
连边
A
−
>
B
,
边
权
为
0
A->B,边权为0
A−>B,边权为0,即
B
B
B分的至少等于
A
A
A分的
建立一个起点
S
S
S,连向所有的人,边权为
1
1
1(每个都要分到至少一个),然后跑最长路即可
最后
Σ
i
=
1
n
d
i
s
[
i
]
Σ_{i=1}^{n}dis[i]
Σi=1ndis[i]即为
A
n
s
w
e
r
Answer
Answer
有负环或者自环就输出
−
1
-1
−1
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <algorithm>
#define N 100005
using namespace std;
typedef long long ll;
struct Node { int To, w, nxt; }e[N*10];
int dis[N], ls[N], Ru[N], n, m, cnt, S = 0;
bool vis[N];
queue <int> Q;
void read(int &x)
{
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s >= '0' && s <= '9') { x = x * 10 + (s - '0'); s = getchar(); }
x = x * f;
}
void Addedge(int u, int v, int w)
{
e[++cnt].To = v, e[cnt].w = w, e[cnt].nxt = ls[u], ls[u] = cnt;
}
bool Spfa()
{
while (!Q.empty()) Q.pop();
vis[S] = 1; Q.push(S);
while (!Q.empty())
{
int u = Q.front(); Q.pop();
for(int i = ls[u]; i; i = e[i].nxt)
if (dis[u] + e[i].w > dis[e[i].To])
{
dis[e[i].To] = dis[u] + e[i].w;
++Ru[e[i].To]; if (Ru[e[i].To] > n) return 1;
if(!vis[e[i].To])
vis[e[i].To] = 1, Q.push(e[i].To);
}
vis[u] = 0;
}
return 0;
}
int main()
{
read(n); read(m);
for (int i = 1; i <= m; i++)
{
int opt, A, B;
read(opt); read(A); read(B);
if (opt == 1) Addedge(A, B, 0), Addedge(B, A, 0);
if (opt == 2)
{
if (A == B) { printf("-1\n"); return 0; }
Addedge(A, B, 1);
}
if (opt == 3) Addedge(B, A, 0);
if (opt == 4)
{
if (A == B) { printf("-1\n"); return 0; }
Addedge(B, A, 1);
}
if (opt == 5) Addedge(A, B, 0);
}
for (int i = n; i >= 1; i--) Addedge(S, i, 1);
if (Spfa()) printf("-1\n");
else
{
ll Answer = 0;
for (int i = 1; i <= n; i++) Answer = Answer + dis[i];
printf("%lld\n", Answer);
}
return 0;
}