• 《算法竞赛进阶指南》差分约束 区间


    给定 n 个区间 [ai,bi] 和 n 个整数 ci。

    你需要构造一个整数集合 Z,使得 ∀i∈[1,n],Z 中满足 ai≤x≤bi 的整数 x 不少于 ci 个。

    求这样的整数集合 Z 最少包含多少个数。

    输入格式

    第一行包含整数 n。

    接下来 n 行,每行包含三个整数 ai,bi,ci。

    输出格式

    输出一个整数表示结果。

    数据范围

    1≤n≤50000,
    0≤ai,bi≤50000,
    1≤ci≤bi−ai+1

    输入样例:

    1. 5
    2. 3 7 3
    3. 8 10 3
    4. 6 8 1
    5. 1 3 1
    6. 10 11 1

    输出样例:

    6

    典型的差分约束问题若不懂差分约束的可以看看这篇:(15条消息) 《图论:差分约束算法详解 + 算法证明》+ 模板题:糖果_wsh1931的博客-CSDN博客

    首先他求的是最小值,所以我们要用最长路

    假设:s[i]为从1 - i 中选择了多少个数

    题目给的数据范围是从0 - 5000我们为了遍历到所有点,即建立超级源点可以将0 - 50000映射成1 - 50001;

    由题意我们可以得到上述结论

    1: s[0] = 0

    2: s[i] - s[i - 1] <= 1(即第i个数最多只能选一个)-> s[i - 1] >= s[i] - 1;

    3: s[b] - s[a - 1] >= c (a, b, c)为题目输入的从区间[a, b]中选择的数不少于c个 -> s[b] >= s[a - 1] + c

    4: s[i] >= s[i - 1] (即从前i个数中选择的数比从前i - 1个数中选择的数多)

    又因为答案肯定有解,所以不需要判断是否无解

    然后我们验证一下从源点出发是不是可以遍历所有点由结论4可以我们可以从0 -> 1. 1-> 2......n - 1 -> n因此可以遍历所有点

    建图的边数:结论2, 3, 4所需要建立的边数各位N所以总共需要建立3 * N条边

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. const int N = 50010, M = 3 * N;
    7. int n;
    8. bool st[N];
    9. int dist[N];
    10. int h[N], e[M], ne[M], w[M], idx;
    11. void add(int a, int b, int c)
    12. {
    13. e[idx] = b;
    14. w[idx] = c;
    15. ne[idx] = h[a];
    16. h[a] = idx;
    17. idx ++ ;
    18. }
    19. void spfa()//求最小值用最长路
    20. {
    21. memset(dist, -0x3f, sizeof dist);
    22. dist[0] = 0;
    23. queue<int> q;
    24. q.push(0);
    25. while (q.size())
    26. {
    27. auto t = q.front();
    28. q.pop();
    29. st[t] = false;
    30. for (int i = h[t]; i != -1; i = ne[i])
    31. {
    32. int j = e[i];
    33. if (dist[j] < dist[t] + w[i])
    34. {
    35. dist[j] = dist[t] + w[i];
    36. if (!st[j])
    37. {
    38. st[j] = true;
    39. q.push(j);
    40. }
    41. }
    42. }
    43. }
    44. }
    45. int main()
    46. {
    47. cin >> n;
    48. memset(h, -1, sizeof h);
    49. for (int i = 1; i < N; i ++ )//结论2,4;
    50. {
    51. add(i, i - 1, -1);
    52. add(i - 1, i, 0);
    53. }
    54. int res = 0;
    55. while (n -- )
    56. {
    57. int a, b, c;
    58. scanf("%d %d %d", &a, &b, &c);
    59. a ++ , b ++ ;//将0 - 50000映射成1 - 50001
    60. res = max(res, b);//求出前res个数中至少选择了多少个数
    61. add(a - 1, b, c);
    62. }
    63. spfa();
    64. cout << dist[res] << endl;//前res个数中共选择了多少个数
    65. return 0;
    66. }

  • 相关阅读:
    lvgl显示中文和自定义图标
    云计算就业方向及前景怎么样
    Linux驱动开发(四)---树莓派内核编译
    保险集团CMAF想成为法国量子优势“第一个吃螃蟹的人”
    regionserver请求不均匀
    C语言编译原理
    vue3使用windicss
    技术分享 | 黑盒测试方法论—等价类
    python学习思路
    为什么高精度机器人普遍使用谐波减速器而不是普通减速器?
  • 原文地址:https://blog.csdn.net/qq_61935738/article/details/126686639