算法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\) 可还行

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 25;
int n, ans, cnt[N], dis[N], R[N], num[N];
int tt, q[N];
bool st[N];
/*
最长路
0 <= Si - S(i - 1)
*/
//把边 (u, v, w) 松弛
bool inline upd(int u, int v, int w) {
if(dis[u] + w > dis[v]) {
dis[v] = dis[u] + w;
cnt[v] = cnt[u] + 1;
if(cnt[v] >= 25) return false;
if(!st[v]) q[++tt] = v, st[v] = true;
}
return true;
} // 返回是否存在可行解
bool spfa() {
memset(dis, -0x3f, sizeof dis);
memset(st, false, sizeof st);
memset(cnt, 0, sizeof cnt);
// 数组模拟栈 更容易找到环
tt = 0;
q[++tt] = 0; dis[0] = 0;
while(tt) {
int u = q[tt--];
st[u] = false;
// 严格保证 s[24] = ans
if(u == 0 && !upd(0, 24, ans)) return false;
if(u == 24 && !upd(24, 0, -ans)) return false;
// s[i] - s[i - 1] >= 0
if(u < 24 && !upd(u, u + 1, 0)) return false;
// s[i] - s[i - 1] <= num[i]
if(u > 0 && !upd(u, u - 1, -num[u])) return false;
//s[i] - s[i - 8] >= R[i]
if(u <= 16 && !upd(u, u + 8, R[u + 8])) return false;
// s[i] + s[24] - s[24 - i] >= R[i]
if(u >= 17 && !upd(u, u - 16, R[u - 16] - ans)) return false;
}
return true;
}
int main() {
int T; scanf("%d", &T);
while(T--) {
memset(num, 0, sizeof num);
for (int i = 1; i < N; i++) scanf("%d", R + i);
scanf("%d", &n);
for (int i = 1, x; i <= n; i++)
scanf("%d", &x), x++, num[x]++; bool ok = false;
// 枚举 s24, s24 就是 答案
for (ans = 0; ans <= n; ans++) {
if(spfa()) {
printf("%d\n", ans);
ok = true;
break;
}
}
if(!ok) puts("No Solution");
}
return 0;
}

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

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

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

\(3ms\) 可还行

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 25;
int n, cnt[N], dis[N], R[N], num[N];
int tt, q[N];
bool st[N];
/*
最长路
0 <= Si - S(i - 1)
*/
//把边 (u, v, w) 松弛
bool inline upd(int u, int v, int w) {
if(dis[u] + w > dis[v]) {
dis[v] = dis[u] + w;
cnt[v] = cnt[u] + 1;
if(cnt[v] >= 25) return false;
if(!st[v]) q[++tt] = v, st[v] = true;
}
return true;
} // 返回是否存在可行解
bool spfa(int s24) {
memset(dis, -0x3f, sizeof dis);
memset(st, false, sizeof st);
memset(cnt, 0, sizeof cnt);
// 数组模拟栈 更容易找到环
tt = 0;
q[++tt] = 0; dis[0] = 0;
while(tt) {
int u = q[tt--];
st[u] = false;
// 严格保证 s[24] = s24
if(u == 0 && !upd(0, 24, s24)) return false;
if(u == 24 && !upd(24, 0, -s24)) return false;
// s[i] - s[i - 1] >= 0
if(u < 24 && !upd(u, u + 1, 0)) return false;
// s[i] - s[i - 1] <= num[i]
if(u > 0 && !upd(u, u - 1, -num[u])) return false;
//s[i] - s[i - 8] >= R[i]
if(u <= 16 && !upd(u, u + 8, R[u + 8])) return false;
// s[i] + s[24] - s[24 - i] >= R[i]
if(u >= 17 && !upd(u, u - 16, R[u - 16] - s24)) return false;
}
return true;
}
int main() {
int T; scanf("%d", &T);
while(T--) {
memset(num, 0, sizeof num);
for (int i = 1; i < N; i++) scanf("%d", R + i);
scanf("%d", &n);
for (int i = 1, x; i <= n; i++)
scanf("%d", &x), x++, num[x]++; int l = 0, r = n;
while(l < r) {
int mid = (l + r) >> 1;
if(spfa(mid)) r = mid;
else l = mid + 1;
}
if(spfa(r)) printf("%d\n", r);
else puts("No Solution");
}
return 0;
}

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. mysql调优从书写sql开始

    理论知识 MySQL 的运行机制 Mysql 的SQL关键字执行顺序 1.MySQL 的优化方案有哪些? MySQL 数据库常见的优化手段分为三个层面:SQL 和索引优化.数据库结构优化.系统硬件优化 ...

  2. springboot做邮件发送功能时报错No qualifying bean of type 'org.springframework.mail.javamail.JavaMailSender' available:的问题解决方案

    1.检查application.yml中的配置是否正确 spring.mail.host=smtp.xxx.comspring.mail.username=xxx@xxx.comspring.mail ...

  3. PicGo+jsDelivr+GitHub搭建免费图床,Typora使用图床

    Github配置 首先,创建一个GitHub账号 然后添加一个仓库 创建完后点头像,Setting 然后点击Developer settings 然后点击Personal access tokens ...

  4. composer的autoload来自动加载自己编写的函数库与类库?

    1.使用命令composer init生成composer.json文件,并编辑autoload选项内容如下: 其中又包含主要的两个选项: files 和 psr-4. files就是需要compos ...

  5. 云服务器-Ubuntu更新系统版本-更新Linux内核-服务器安全配置优化-防反弹shell

    购入了一台阿里云的ESC服务器,以前都用CentOS感觉Yum不怎么方便,这次选的Ubuntu16.04.7 搭好服务之后做安全检查,发现Ubuntu16.04版本漏洞众多:虽然也没有涉及到16.04 ...

  6. 详讲FL Studio通道设置菜单

    我们在FL Studio"通道设置按钮"上右击鼠标就会弹出一个设置菜单,它包含了通道操作的各种常用命令.下文小编将会为大家详细讲解这些命令的具体作用,一起来学习吧! 1.首先,我们 ...

  7. 洛谷 P1360 [USACO07MAR]Gold Balanced Lineup G (前缀和+思维)

    P1360 [USACO07MAR]Gold Balanced Lineup G (前缀和+思维) 前言 题目链接 本题作为一道Stl练习题来说,还是非常不错的,解决的思维比较巧妙 算是一道不错的题 ...

  8. FL Studio新手入门:FL Studio五大常用按钮介绍

    我们打开FL Studio编曲软件会发现界面中有好多的菜单和窗口,这些窗口每个都有其单独的功能.今天小编主要给大家详细讲解下FL Studio水果软件的五大常用按钮. 1.首先我,我们双击桌面的水果图 ...

  9. LaTex源文件的基本结构

    默认编译器设置: Utf-8设置: 相关代码与注释: 显示效果:

  10. 项目、地铁/公交、游戏签到、项目上线后发现新bug该怎么处理

    项目:1.提前分配好业务(每个人该干什么 )2.提前召开会议3.提前挑好人4.准备项目思维导图5.提前审阅项目6.为确保项目按期交付 把控好时间7.给员工提前打好招呼 (提醒加班)8.建立好安全机制9 ...