糖果
【题目描述】
幼儿园里有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。
【样例输入】
5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1
【样例输出】
11
【数据范围】
对于30%的数据,保证N<=100
对于100%的数据,保证N<=100000
对于所有的数据,保证K<=100000,1<=X<=5,1<=A, B<=N
SCOI2010第一题。去年做过一样的题,当时AC了,但是今年又考只得了60分。因为没有认真总结。
现在知道为什么会错了。因为这道题只能够建正边,不能建负边。
因为差分约束的解是不唯一的,然后本题需要求最小解。因此只能从小到大松弛,逼近解。
假如是求最大解,则只能建负边。
另外这次是用的相对高度的办法,首先把所有的点全部入队。
听wjj讲有别的方法。即:从0到所有点建一条权值为0的边。即d[ i ] >= d[ 0 ]
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <queue>
typedef long long ll;
using std::cout;
using std::cin;
std::queue<long> que;
long n;long k;
struct node
{
long i;
long val;
node* next;
};
node* head[100010];
const long inf = 0x70707070;
bool vis[100010];
long long dis[100010];
long cnt[100010];
void spfa()
{
memset(vis,1,sizeof(vis));///
memset(dis,0,sizeof(dis));
for (long i=1;i<n+1;i++)
que.push(i);
while (!que.empty())
{
long u = que.front();
vis[u] = false;
que.pop();
for (node* vv=head[u];vv;vv=vv->next)
{
long v = vv->i;
if (dis[v] < dis[u]+(ll)vv->val)
{
cnt[v] ++;
if (cnt[v] >= n)
{
cout << -1;
exit(0);
}
dis[v] = dis[u]+(ll)vv->val;
if (!vis[v])
{
vis[v] = true;
que.push(v);
}
}
}
}
}
void insert(long a,long b,long c)
{
node* nn = new node;
nn->i = b;
nn->val = c;
nn->next = head[a];
head[a] = nn;
}
int main()
{
freopen("candy.in","r",stdin);
freopen("candy.out","w",stdout);
scanf("%ld%ld",&n,&k);
for (long i=1;i<k+1;i++)
{
long x;long a;long b;
scanf("%ld%ld%ld",&x,&a,&b);
if ((x==2||x==4)&&a==b){cout<<-1;return 0;}
switch (x)
{
case 2:insert(a,b,1);break;
case 3:insert(b,a,0);break;
case 4:insert(b,a,1);break;
case 5:insert(a,b,0);break;
case 1:
insert(a,b,0);
insert(b,a,0);
break;
}
}
spfa();
ll ans = 0;
ll min = inf;
for (long i=1;i<n+1;i++)
{
if (min > dis[i]) min = dis[i];
ans += dis[i];
//cout << i << " " << dis[i] << std::endl;
}
cout << ans-(min-1)*n;
return 0;
}