bzoj2330: [SCOI2011]糖果 差分约束系统
幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候,lxhgww需要满足小朋友们的K个要求。幼儿园的糖果总是有限的,lxhgww想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。
Input
输入的第一行是两个整数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个小朋友分到的糖果;
Output
输出一行,表示lxhgww老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出-1。
题解:差分约束系统,求相当于求0到1~n的差值最小,根据差值求最长路,如果有不等式a>=b+c,那么从b连一条权值为c的边到a,然后由于每个小朋友不能没有糖果,所以a>=1,从0开始跑一边最长路,求和即可(为什么可以?可以这么看,为了满足不等式,从b到a权值最小都是c,假设有多条b到a的权值边,那么肯定要选权值最大的那条边(因为要满足所有不等式),然后其他点同理,所以就是求最长路,从0开始跑一边单源最长路即可,)值得注意的是这题卡spfa,注意加边顺序,以及入队次数,还有自环的情况
/**************************************************************
Problem: 2330
User: walfy
Language: C++
Result: Accepted
Time:356 ms
Memory:8032 kb
****************************************************************/
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define mod (1000000007)
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
const double g=10.0,eps=1e-12;
const int N=100000+10,maxn=400000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
struct edge{
int to,Next,c;
}e[maxn];
int cnt,head[N];
void init()
{
cnt=0;
memset(head,-1,sizeof head);
}
void add(int u,int v,int c)
{
e[cnt].to=v;
e[cnt].c=c;
e[cnt].Next=head[u];
head[u]=cnt++;
}
ll dis[N];
int n,k,in[N];
bool vis[N];
bool spfa()
{
queue<int>q;
for(int i=1;i<=n;i++)dis[i]=-1e18;
dis[0]=0;
memset(vis,0,sizeof vis);
vis[0]=1;in[0]++;
q.push(0);
while(!q.empty())
{
int u=q.front();q.pop();vis[u]=0;
for(int i=head[u];~i;i=e[i].Next)
{
int x=e[i].to;
// printf("%d %d\n",dis[x],dis[u]+e[i].c);
if(dis[x]<dis[u]+e[i].c)
{
dis[x]=dis[u]+e[i].c;
if(!vis[x])
{
vis[x]=1;
q.push(x);
in[x]++;
if(in[x]>=n+1)return 0;
}
}
}
}
return 1;
}
int main()
{
scanf("%d%d",&n,&k);
init();
int f=1;
while(k--)
{
int x,a,b;
scanf("%d%d%d",&x,&a,&b);
if(x==1)add(a,b,0),add(b,a,0);
else if(x==2){if(a==b)f=0;add(a,b,1);}
else if(x==3)add(b,a,0);
else if(x==4){if(a==b)f=0;add(b,a,1);}
else add(a,b,0);
}
for(int i=n;i>=1;i--)add(0,i,1);
// for(int i=0;i<=n;i++)printf("%d %lld\n",i,dis[i]);
if(f==0||!spfa())puts("-1");
else
{
ll ans=0;
for(int i=1;i<=n;i++)ans+=dis[i];
printf("%lld\n",ans);
}
return 0;
}
/********************
5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1
********************/