算法1: 差分约束 + 枚举 O(Tn2028)

由于牵扯到 \([i - 8 + 1, i]\) 这段区间的和的约束,所以用前缀和更好表达一些。

设 \(num[i]\)表示 \(i\) 时刻有多少人申请上岗, \(x[i]\) 为 \(i\) 时刻实际上岗的人数 ,\(s\) 为 \(x\) 的前缀和数组。


则应该满足的约束条件是:

  1. 上岗人数不能负数,即 \(s[i] - s[i - 1] >= 0\)

  2. 实际上岗人数不能超过申请人数,即 \(s[i] - s[i - 1] <= num[i]\)

  3. \(i\) 时刻所在人数,即 \([i - 7, i]\) 区间内的上岗人数要大于等于最小需求 \(R\)

    由于存在环,即 \(23\) 到 \(24\),再到 \(0\) 时刻,所以要分类讨论:

    • 当 \(i >= 8\) 时,\(s[i] - s[i - 8] >= R[i]\)
    • 当 \(i <= 7\) 时,\(s[i] + s[24] - s[24 - i] >= R[i]\)

显然这是一个明显的差分约束问题,由于求最小人数,所以用最长路转化:

  1. \(s[i] >= s[i - 1]\) 即 \(add(i - 1, i, 0)\)
  2. \(s[i] - num[i] <= s[i - 1]\) 即 \(add(i, i - 1, -num[i])\)
  3. \(s[i - 8] + R[i] <= s[i]\) 即 \(add(i - 8, i, R[i])\)
  4. \(s[16 + i] + R[i] - s[24] <= s[i]\),不会连边了hhhh

最后一种约束关系我们不会连边的原因无非是出现了三个变量,但我们可以发现:

  • 所有最后一种约束关系都有 \(s[24]\) 变量,其实这个东西就是我们求的答案,所以我们可以枚举 \(s[24]\) 的值,把它变成常量就行啦!然后就可以 \(add(16 + i, i, R[i] - s[24])\)

\(Tips:\)

  1. 关于建图,其实可以在线建图,不用僵化建边了嘿嘿。

  2. 发现 \(0\) 肯定所有点,所以不用创造超级源点了,只需从 \(0\) 点出发跑最短路即可。

  3. 不要忘了 $s[24] = $ 我们枚举的数 \(c\)(要严格等于,实现是 大于等于 + 小于等于):

    • \(s[24] <= c\) 即 \(add(24, 0, -c)\)
    • \(s[24] >= c\) 即 \(add(0, 24, c)\)

时间复杂度

这个题中的点数 $ <= 26$,边数 $ <= 26 * 3 = 78$,

所以时间复杂度 \(O(Tn2028)\),足以 \(AC\)

\(5ms\) 可还行

  1. #include <cstdio>
  2. #include <iostream>
  3. #include <cstring>
  4. using namespace std;
  5. const int N = 25;
  6. int n, ans, cnt[N], dis[N], R[N], num[N];
  7. int tt, q[N];
  8. bool st[N];
  9. /*
  10. 最长路
  11. 0 <= Si - S(i - 1)
  12. */
  13. //把边 (u, v, w) 松弛
  14. bool inline upd(int u, int v, int w) {
  15. if(dis[u] + w > dis[v]) {
  16. dis[v] = dis[u] + w;
  17. cnt[v] = cnt[u] + 1;
  18. if(cnt[v] >= 25) return false;
  19. if(!st[v]) q[++tt] = v, st[v] = true;
  20. }
  21. return true;
  22. }
  23. // 返回是否存在可行解
  24. bool spfa() {
  25. memset(dis, -0x3f, sizeof dis);
  26. memset(st, false, sizeof st);
  27. memset(cnt, 0, sizeof cnt);
  28. // 数组模拟栈 更容易找到环
  29. tt = 0;
  30. q[++tt] = 0; dis[0] = 0;
  31. while(tt) {
  32. int u = q[tt--];
  33. st[u] = false;
  34. // 严格保证 s[24] = ans
  35. if(u == 0 && !upd(0, 24, ans)) return false;
  36. if(u == 24 && !upd(24, 0, -ans)) return false;
  37. // s[i] - s[i - 1] >= 0
  38. if(u < 24 && !upd(u, u + 1, 0)) return false;
  39. // s[i] - s[i - 1] <= num[i]
  40. if(u > 0 && !upd(u, u - 1, -num[u])) return false;
  41. //s[i] - s[i - 8] >= R[i]
  42. if(u <= 16 && !upd(u, u + 8, R[u + 8])) return false;
  43. // s[i] + s[24] - s[24 - i] >= R[i]
  44. if(u >= 17 && !upd(u, u - 16, R[u - 16] - ans)) return false;
  45. }
  46. return true;
  47. }
  48. int main() {
  49. int T; scanf("%d", &T);
  50. while(T--) {
  51. memset(num, 0, sizeof num);
  52. for (int i = 1; i < N; i++) scanf("%d", R + i);
  53. scanf("%d", &n);
  54. for (int i = 1, x; i <= n; i++)
  55. scanf("%d", &x), x++, num[x]++;
  56. bool ok = false;
  57. // 枚举 s24, s24 就是 答案
  58. for (ans = 0; ans <= n; ans++) {
  59. if(spfa()) {
  60. printf("%d\n", ans);
  61. ok = true;
  62. break;
  63. }
  64. }
  65. if(!ok) puts("No Solution");
  66. }
  67. return 0;
  68. }

算法2: 差分约束 + 二分 O(T2028logN)

显然,答案具有单调性(若允许上岗的人越多,越容易满足条件)。

所以可以二分答案 \(LOL\)。

\(3ms\) 可还行

  1. #include <cstdio>
  2. #include <iostream>
  3. #include <cstring>
  4. using namespace std;
  5. const int N = 25;
  6. int n, cnt[N], dis[N], R[N], num[N];
  7. int tt, q[N];
  8. bool st[N];
  9. /*
  10. 最长路
  11. 0 <= Si - S(i - 1)
  12. */
  13. //把边 (u, v, w) 松弛
  14. bool inline upd(int u, int v, int w) {
  15. if(dis[u] + w > dis[v]) {
  16. dis[v] = dis[u] + w;
  17. cnt[v] = cnt[u] + 1;
  18. if(cnt[v] >= 25) return false;
  19. if(!st[v]) q[++tt] = v, st[v] = true;
  20. }
  21. return true;
  22. }
  23. // 返回是否存在可行解
  24. bool spfa(int s24) {
  25. memset(dis, -0x3f, sizeof dis);
  26. memset(st, false, sizeof st);
  27. memset(cnt, 0, sizeof cnt);
  28. // 数组模拟栈 更容易找到环
  29. tt = 0;
  30. q[++tt] = 0; dis[0] = 0;
  31. while(tt) {
  32. int u = q[tt--];
  33. st[u] = false;
  34. // 严格保证 s[24] = s24
  35. if(u == 0 && !upd(0, 24, s24)) return false;
  36. if(u == 24 && !upd(24, 0, -s24)) return false;
  37. // s[i] - s[i - 1] >= 0
  38. if(u < 24 && !upd(u, u + 1, 0)) return false;
  39. // s[i] - s[i - 1] <= num[i]
  40. if(u > 0 && !upd(u, u - 1, -num[u])) return false;
  41. //s[i] - s[i - 8] >= R[i]
  42. if(u <= 16 && !upd(u, u + 8, R[u + 8])) return false;
  43. // s[i] + s[24] - s[24 - i] >= R[i]
  44. if(u >= 17 && !upd(u, u - 16, R[u - 16] - s24)) return false;
  45. }
  46. return true;
  47. }
  48. int main() {
  49. int T; scanf("%d", &T);
  50. while(T--) {
  51. memset(num, 0, sizeof num);
  52. for (int i = 1; i < N; i++) scanf("%d", R + i);
  53. scanf("%d", &n);
  54. for (int i = 1, x; i <= n; i++)
  55. scanf("%d", &x), x++, num[x]++;
  56. int l = 0, r = n;
  57. while(l < r) {
  58. int mid = (l + r) >> 1;
  59. if(spfa(mid)) r = mid;
  60. else l = mid + 1;
  61. }
  62. if(spfa(r)) printf("%d\n", r);
  63. else puts("No Solution");
  64. }
  65. return 0;
  66. }

Acwing 393. 雇佣收银员的更多相关文章

  1. 湖南附中模拟day1 收银员

    4.1 题意描述花花家的超市是 24 小时营业的,现在需要招聘收银员.超市每个小时都需要不同数量的收银员,用 ai 表示一天中 i 点到 i + 1 点这一小时内需要的收银员数量,特别地 a23 表示 ...

  2. poj1275收银员——差分约束

    题目:http://poj.org/problem?id=1275 做的第一道差分约束题... 首先,根据题意得出一些不等关系(f为前缀和雇佣人数): 0 <= f[i] - f[i-1] &l ...

  3. 【NOIP模拟赛】收银员(一道差分约束好题)

    /* s[]表示最优方案的序列中的前缀和,那么s[23]就是最优方案 由题意我们可以列出这样一些式子: s[i]+s[23]-s[16+i]>=a[i] (i-8<0) s[i]-s[i- ...

  4. 移动零售批发行业新的技术特色-智能PDA手持移动扫描打印销售开单收银仪!!

    提起便利店或者超市,大家的第一印象一定是前台那个笨重的POS机和站在POS机后的收银员.传统的零售店中,笨重的POS机随处可见. 变革前,零售盘点多烦忧 一个顾客要结账,就需要通过POS机.小票打印机 ...

  5. C++ 大作业 超市收银系统

    #include<iostream> #include<fstream> #include<string> #include<iomanip> #inc ...

  6. 互联网+下PDA移动智能手持POS超市收银开单软件

    是一套专为中小超市.专卖店设计的收银管理软件,广泛应用于中小超市(百货商店).化妆品店.婴幼儿用品店.玩具店.保健品店.茶叶店. 电器.文具图书.手机通讯器材店等行业的中小型店面店铺.该系统具有完善的 ...

  7. PDA 收银系统PDA手持打印扫描枪 销售开单 收银 扫描打印一体机

    在零售方面也有很好的应用.如在一些高端品牌零售店,营业员可以随身导购,一站式完成了商品销售和收银,很是受消费者追捧,符合了企业对客户体验以及行业领先的追求. PDA收银系统是一款多功能可以取代专业收银 ...

  8. 浩瀚移动POS收银开单扫描解决方案PDA仓储系统,无线批发,移动批发,无线POS,无线销售APP-车销管理PDA

    适用范围 各种业态的批发商铺.批发市场.订货会.展销会.配送中心仓库…… 产品简介 随着移动技术与智能PDA设备的迅猛发展,中国已经跨步进入移动信息化社会.移动商务是移动信息社会的重要载体与形式,它开 ...

  9. PDA移动POS开单扫描打票收银系统-带来零售批发 新的技术 新的手段!!

    手持POS终端高清彩屏,清晰.美观.大方,适用于仓库.超市.服装.食品.批发零售.手机电脑等企业管理.可与管理软件灵活对接.1:员工记不住价格,产品名称,只要有PDA扫描,价格,库存,直接开销售单,打 ...

随机推荐

  1. UNP——第五章,TCP客户/服务程序

    tcpser void str_echo(int sockfd) { long arg1, arg2; ssize_t n; char line[MAXLINE]; for ( ; ; ) { if ...

  2. linux 图解笔记

  3. Microsoft Visual C++ 2005 SP1无法安装

    安装时出现需要Microsoft Visual C++ 2005 Redistributble对话框, 里面说Command line option syntax error . Type Comma ...

  4. 测试_QTP使用实例

    1. QTP简介 1.1QTP功能与特点 QTP是QuickTest Professional的简称,是一种自动化软件测试工具.在软件的测试过程中,QTP主要来用来通过已有的测试脚本执行重复的手动测试 ...

  5. Vue + ElementUI 后台管理模板推荐

    最近学习和项目都用到了Vue和ElementUI,自己不是专业前端,搞这些UI上的东西还是有些难度,这里推荐两个Vue + ElementUI后台管理模板 vue-element-admin vue- ...

  6. Javaweb项目页面实时显示后台处理结果

    http://www.cnblogs.com/dong-xu/p/6701271.html 此博文甚好,项目参照博主代码可实现. 前端页面: <%@ page language="ja ...

  7. MongoDB动态建表方案(官方原生驱动)

    MongoDB动态建表方案(官方原生驱动) 需求前提:表名动态,表结构静态,库固定 1.导入相关依赖 <dependency> <groupId>org.mongodb< ...

  8. Android呼吸灯添加

    平台:mtk 一.hal层入口    Lights.c (vendor\mediatek\proprietary\hardware\liblights)     char const*const RE ...

  9. 什么是NTFS文件格式

    说到磁盘格式,想必大家对于NTFS格式并不陌生.我们使用的u盘等硬盘设备很多都应用了此格式.NTFS文件格式究竟是什么?它都有哪些特点?今天,小编将利用这篇文章为大家进行介绍. 一.什么是NTFS文件 ...

  10. try-with-resources和multi-catch的使用

    1.首先说一下以前开发中我们在处理异常时,我们会使用try-catch-finally来处理异常. //使用try-catch-finallypublic static void main(Strin ...