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
********************/
posted @ 2018-06-04 00:36  walfy  阅读(197)  评论(0编辑  收藏  举报