• 【洛谷】P3275 糖果


    题目地址:

    https://www.luogu.com.cn/problem/P3275

    题目描述:
    幼儿园里有 N N N个小朋友, lxhgww \text{lxhgww} lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候, lxhgww \text{lxhgww} lxhgww需要满足小朋友们的 K K K个要求。幼儿园的糖果总是有限的, lxhgww \text{lxhgww} lxhgww想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。

    输入格式:
    输入的第一行是两个整数 N N N K K K。接下来 K K K行,表示这些点需要满足的关系,每行 3 3 3个数字, X X X A A A B B 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个小朋友分到的糖果;

    输出格式:
    输出一行,表示 lxhgww \text{lxhgww} lxhgww老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出 − 1 -1 1

    数据范围:
    对于 30 % 30\% 30%的数据,保证 N ≤ 100 N\leq100 N100
    对于 100 % 100\% 100%的数据,保证 N ≤ 100000 N\leq100000 N100000
    对于所有的数据,保证 K ≤ 100000 , 1 ≤ X ≤ 5 , 1 ≤ A , B ≤ N K\leq100000, 1\leq X\leq5, 1\leq A, B\leq N K100000,1X5,1A,BN

    标准做法是用最长路求差分约束,这里还可以用缩点 + 拓扑排序来做。先按差分约束最长路的手法建图(该图里每条边都非负),然后在只考虑 0 0 0边的情况下缩点,这样每个团的糖果数应该相等。接着建出缩点后的图,如果某个团内部有非零边,则无解;否则可以利用拓扑排序来求最长路,然后累加起来即可。代码如下:

    #include 
    #include 
    #include 
    using namespace std;
    
    const int N = 1e5 + 10, M = 4e5 + 10;
    int n, m;
    int h[N], hs[N], e[M], ne[M], w[M], idx;
    int dfn[N], low[N], timestamp;
    int stk[N], top;
    bool in_stk[N];
    int id[N], scc_cnt, sz[N];
    int ind[N], dist[N];
    queue<int> q;
    
    void add(int a, int b, int c, int h[]) {
      e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
    }
    
    void tarjan(int u) {
      dfn[u] = low[u] = ++timestamp;
      stk[top++] = u, in_stk[u] = true;
      for (int i = h[u]; ~i; i = ne[i]) {
        if (w[i]) continue;
        int v = e[i];
        if (!dfn[v]) {
          tarjan(v);
          low[u] = min(low[u], low[v]);
        } else if (in_stk[v]) low[u] = min(low[u], dfn[v]);
      }
    
      if (dfn[u] == low[u]) {
        scc_cnt++;
        int y;
        do {
          y = stk[--top];
          in_stk[y] = false;
          id[y] = scc_cnt;
          sz[scc_cnt]++;
        } while (y != u);
      }
    }
    
    int main() {
      memset(h, -1, sizeof h);
      memset(hs, -1, sizeof hs);
      scanf("%d%d", &n, &m);
      for (int i = 1; i <= n; i++) add(0, i, 0, h);
      while (m--) {
        int op, a, b;
        scanf("%d%d%d", &op, &a, &b);
        // 这里提前特判一下无解的情形
        if (a == b) {
          if (op == 2 || op == 4) {
            puts("-1");
            return 0;
          }
          continue;
        }
        if (op == 1) add(a, b, 0, h), add(b, a, 0, h);
        else if (op == 2) add(a, b, 1, h);
        else if (op == 3) add(b, a, 0, h);
        else if (op == 4) add(b, a, 1, h);
        else add(a, b, 0, h);
      }
    
      // 缩点
      for (int i = 1; i <= n; i++)
        if (!dfn[i])
          tarjan(i);
    
      // 建立缩点后的图
      for (int i = 1; i <= n; i++)
        for (int j = h[i]; ~j; j = ne[j]) {
          int x = id[i], y = id[e[j]];
          if (x != y) {
            ind[y]++;
            add(x, y, w[j], hs);
          } else if (w[j]) {
            puts("-1");
            return 0;
          }
        }
    
      // 拓扑排序
      for (int i = 1; i <= scc_cnt; i++)
        if (!ind[i]) {
          q.push(i);
          dist[i] = 1;
        }
    
      n = 0;
      while (q.size()) {
        n++;
        int t = q.front(); q.pop();
        for (int i = hs[t]; ~i; i = ne[i]) {
          int v = e[i];
          dist[v] = max(dist[v], dist[t] + w[i]);
          ind[v]--;
          if (!ind[v]) q.push(v);
        }
      }
    
      // 有环,说明无解
      if (n < scc_cnt) puts("-1");
      else {
        long res = 0;
        for (int i = 1; i <= scc_cnt; i++) res += (long) sz[i] * dist[i];
        printf("%ld\n", res);
      }
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112

    时间复杂度 O ( N + K ) O(N+K) O(N+K),空间 O ( N ) O(N) O(N)

  • 相关阅读:
    Docker基础(简单易懂)
    FPGA实现电机转速PID控制
    Flask 学习-39.Flask-RESTful 请求参数校验inputs
    Go 语言基础
    unity无法激活认证、无法保存许可证、及unity package manager Error
    pandas中的数据结构
    微信浏览器大字体模式 按钮文字居中用line-height 显示异常
    BeanUtils.copyProperties在spring包和apache包中使用情况
    Cisco 交换机利用CDP数据自动绘制网络拓扑图[drawio]-实践
    工业机器人模拟题
  • 原文地址:https://blog.csdn.net/qq_46105170/article/details/126326827