• BZOJ 2330 糖果 差分约束求最小值


    题目链接:

    https://www.lydsy.com/JudgeOnline/problem.php?id=2330

    题目大意:

    幼儿园里有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。

    思路:

    差分约束系统求最小值,要用最长路。

     差分约束系统求最大值时,构造边按照:d[v] - d[u] <=  Edge[u][v] (u->v连边),求解时按照最短路求解(也就是松弛的时候按照原来的方式进行松弛)

    求最小值时,构造边按照:d[v] - d[u] >= Edge[u][v](u->v连边),求解时按照最长路进行求解(松弛的时候和原来相反)

    坑:

    添加边的时候需要逆序添加,数据原因。(也可以将要添加的边存起来,随机一下添加)

    需要特判自环的情况不然也会T

      1 #include<bits/stdc++.h>
      2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf
      3 #define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时
      4 #define Min(a, b) ((a) < (b) ? (a) : (b))
      5 #define Mem(a) memset(a, 0, sizeof(a))
      6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1))
      7 #define MID(l, r) ((l) + ((r) - (l)) / 2)
      8 #define lson ((o)<<1)
      9 #define rson ((o)<<1|1)
     10 #define Accepted 0
     11 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂
     12 using namespace std;
     13 inline int read()
     14 {
     15     int x=0,f=1;char ch=getchar();
     16     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     17     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     18     return x*f;
     19 }
     20 typedef long long ll;
     21 const int maxn = 1000000 + 10;
     22 const int MOD = 1000000007;//const引用更快,宏定义也更快
     23 const ll INF = 1e12 + 7;
     24 const double eps = 1e-6;
     25 
     26 struct edge
     27 {
     28     ll u, v;
     29     ll w;
     30     ll next;
     31 };
     32 edge a[maxn];
     33 ll head[maxn], node;
     34 void addedge(ll u, ll v, ll w)
     35 {
     36     a[node].u = u;
     37     a[node].v = v;
     38     a[node].w = w;
     39     a[node].next = head[u];
     40     head[u] = node++;
     41 }
     42 
     43 ll cnt[maxn];
     44 bool vis[maxn];
     45 ll d[maxn];
     46 ll n;
     47 bool SPFA(ll u)
     48 {
     49     queue<ll>q;
     50     memset(vis, 0, sizeof(vis));
     51     memset(cnt, 0, sizeof(cnt));
     52     for(int i = 1; i <= n; i++)d[i] = -INF;//赋值成最小值 来求解最长路
     53     d[u] = 0;
     54     vis[u] = 1;
     55     q.push(u);
     56     while(!q.empty())
     57     {
     58         ll u = q.front();
     59         q.pop();
     60         vis[u] = 0;
     61         for(ll i = head[u]; i != -1; i = a[i].next)
     62         {
     63             edge& e = a[i];
     64             if(d[e.v] < d[u] + e.w)//求最长路松弛符号改变
     65             {
     66                 d[e.v] = d[u] + e.w;
     67                 if(!vis[e.v])
     68                 {
     69                     q.push(e.v);
     70                     vis[e.v] = 1;
     71                     if(++cnt[e.v] >= n)return false;
     72                 }
     73             }
     74         }
     75     }
     76     return true;
     77 }
     78 int main()
     79 {
     80     memset(head, -1, sizeof(head));
     81     ll k, x, a, b;
     82     scanf("%lld%lld", &n, &k);
     83     for(ll i = n; i >= 1; i--)addedge(0, i, 0);
     84     bool flag = 0;
     85     while(k--)
     86     {
     87         scanf("%lld%lld%lld", &x, &a, &b);
     88         if(x == 1)
     89         {
     90             addedge(a, b, 0);
     91             addedge(b, a, 0);
     92         }
     93         else if(x == 2)
     94         {
     95             if(a == b)flag = 1;
     96             addedge(a, b, 1);
     97         }
     98         else if(x == 3)
     99         {
    100             addedge(b, a, 0);
    101         }
    102         else if(x == 4)
    103         {
    104             if(a == b)flag = 1;
    105             addedge(b, a, 1);
    106         }
    107         else
    108         {
    109             addedge(a, b, 0);
    110         }
    111     }
    112     if(!flag && SPFA(0))
    113     {
    114         ll ans = 0;
    115         for(ll i = 1; i <= n; i++)ans += d[i] + 1;//加上最开始的1
    116         printf("%lld
    ", ans);
    117     }
    118     else
    119     {
    120         printf("-1
    ");
    121     }
    122     return Accepted;
    123 }
  • 相关阅读:
    php设计模式-工厂模式(一)
    php Pthread 线程 互斥锁
    php Pthread 多线程 Worker
    PHP多进程实例
    C# this 关键字
    .NET FileStream文件流,StreamReader文本流,MemoryStream内存流几种流的实例
    深入理解Static关键字修饰符
    SQL Server 视图
    .NET初识委托
    RSA加密
  • 原文地址:https://www.cnblogs.com/fzl194/p/9697362.html
Copyright © 2020-2023  润新知