Acwing 393. 雇佣收银员
算法1: 差分约束 + 枚举 O(Tn2028)
由于牵扯到 \([i - 8 + 1, i]\) 这段区间的和的约束,所以用前缀和更好表达一些。
设 \(num[i]\)表示 \(i\) 时刻有多少人申请上岗, \(x[i]\) 为 \(i\) 时刻实际上岗的人数 ,\(s\) 为 \(x\) 的前缀和数组。
则应该满足的约束条件是:
上岗人数不能负数,即 \(s[i] - s[i - 1] >= 0\)
实际上岗人数不能超过申请人数,即 \(s[i] - s[i - 1] <= num[i]\)
\(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]\)
显然这是一个明显的差分约束问题,由于求最小人数,所以用最长路转化:
- \(s[i] >= s[i - 1]\) 即 \(add(i - 1, i, 0)\)
- \(s[i] - num[i] <= s[i - 1]\) 即 \(add(i, i - 1, -num[i])\)
- \(s[i - 8] + R[i] <= s[i]\) 即 \(add(i - 8, i, R[i])\)
- \(s[16 + i] + R[i] - s[24] <= s[i]\),不会连边了hhhh
最后一种约束关系我们不会连边的原因无非是出现了三个变量,但我们可以发现:
- 所有最后一种约束关系都有 \(s[24]\) 变量,其实这个东西就是我们求的答案,所以我们可以枚举 \(s[24]\) 的值,把它变成常量就行啦!然后就可以 \(add(16 + i, i, R[i] - s[24])\)
\(Tips:\)
关于建图,其实可以在线建图,不用僵化建边了嘿嘿。
发现 \(0\) 肯定所有点,所以不用创造超级源点了,只需从 \(0\) 点出发跑最短路即可。
不要忘了 $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. 雇佣收银员的更多相关文章
- 湖南附中模拟day1 收银员
4.1 题意描述花花家的超市是 24 小时营业的,现在需要招聘收银员.超市每个小时都需要不同数量的收银员,用 ai 表示一天中 i 点到 i + 1 点这一小时内需要的收银员数量,特别地 a23 表示 ...
- poj1275收银员——差分约束
题目:http://poj.org/problem?id=1275 做的第一道差分约束题... 首先,根据题意得出一些不等关系(f为前缀和雇佣人数): 0 <= f[i] - f[i-1] &l ...
- 【NOIP模拟赛】收银员(一道差分约束好题)
/* s[]表示最优方案的序列中的前缀和,那么s[23]就是最优方案 由题意我们可以列出这样一些式子: s[i]+s[23]-s[16+i]>=a[i] (i-8<0) s[i]-s[i- ...
- 移动零售批发行业新的技术特色-智能PDA手持移动扫描打印销售开单收银仪!!
提起便利店或者超市,大家的第一印象一定是前台那个笨重的POS机和站在POS机后的收银员.传统的零售店中,笨重的POS机随处可见. 变革前,零售盘点多烦忧 一个顾客要结账,就需要通过POS机.小票打印机 ...
- C++ 大作业 超市收银系统
#include<iostream> #include<fstream> #include<string> #include<iomanip> #inc ...
- 互联网+下PDA移动智能手持POS超市收银开单软件
是一套专为中小超市.专卖店设计的收银管理软件,广泛应用于中小超市(百货商店).化妆品店.婴幼儿用品店.玩具店.保健品店.茶叶店. 电器.文具图书.手机通讯器材店等行业的中小型店面店铺.该系统具有完善的 ...
- PDA 收银系统PDA手持打印扫描枪 销售开单 收银 扫描打印一体机
在零售方面也有很好的应用.如在一些高端品牌零售店,营业员可以随身导购,一站式完成了商品销售和收银,很是受消费者追捧,符合了企业对客户体验以及行业领先的追求. PDA收银系统是一款多功能可以取代专业收银 ...
- 浩瀚移动POS收银开单扫描解决方案PDA仓储系统,无线批发,移动批发,无线POS,无线销售APP-车销管理PDA
适用范围 各种业态的批发商铺.批发市场.订货会.展销会.配送中心仓库…… 产品简介 随着移动技术与智能PDA设备的迅猛发展,中国已经跨步进入移动信息化社会.移动商务是移动信息社会的重要载体与形式,它开 ...
- PDA移动POS开单扫描打票收银系统-带来零售批发 新的技术 新的手段!!
手持POS终端高清彩屏,清晰.美观.大方,适用于仓库.超市.服装.食品.批发零售.手机电脑等企业管理.可与管理软件灵活对接.1:员工记不住价格,产品名称,只要有PDA扫描,价格,库存,直接开销售单,打 ...
随机推荐
- 一、智能指针及线程同步总结------linux多线程服务端编程
更新2.0 二.多线程及服务器编程总结------linux多线程服务端编程 https://www.cnblogs.com/l2017/p/11335609.html 三.分布式编程总结------ ...
- sql 训练及总结
1.sql语句中=与in的区别,=是指一对一之间的等于,而in是指一对多之间的:同样的道理,<>与 not in的区别,<>是指一对一之间的不等于,而not in是指一对多之 ...
- ubuntu服务器启动过程中重启卡死的问题解决
在grub默认参数当中添加 GRUB_RECORDFAIL_TIMEOUT=0 写于: 2014年07月23日 更新于: 2015年03月24日
- linux打包 压缩 解压tar常归操作
tar 打包 tar -cvf 打包后路径和文件名.tar 需要打包的路径和文件压缩 tar -zcvf 打包后路径和文件名.tar.gz 需要打包的路径和文件解压 tar -xvf 包名 -C 路径 ...
- no appropriate service handler found,修改数据库的最大连接数,默认150
no appropriate service handler found,频繁进行数据操作的时候,会出现这种错误.例如,当我读取excel时,一次读取好多数据,这个时候需要修改数据库的最大连接数 se ...
- day01-系统基础信息模块
前言:2015年,由于大规模采用云平台虚拟机部署应用,每套应用系统的MySQl.接口机.WEB服务器.文件服务器需要经常进行版本升级.配置更新.安全补丁加固.iptables调整.配置核实,大量的手工 ...
- 下载器Folx教程:智能标签怎么用?
Mac专用下载器Folx的智能标签中内置了图片标签,可以自动分类图片文件,但要如何分类GIF图片呢?其实,我们可以在Folx的标签面板创建动图标签,然后再创建标签专属的下载文件夹,来独立存放GIF格式 ...
- Boom 3D带你聆听《我们的乐队》音乐盛宴
说到前段时间大热的音乐类综艺节目,<我们的乐队>肯定值得一提.<我们的乐队>是由谢霆锋.萧敬腾.王俊凯担任导师,以团队的形式组成各种风格的乐队,并通过同场比拼,最终选出获胜的乐 ...
- Gin + 七牛云对象存储
配置七牛云存储 创建存储空间 拿到密钥 安装七牛云对象存储SDK 推荐go.mod安装 // 将下面地址复制到go.mod,然后执行go mod download github.com/qiniu/a ...
- 学习关注:学习C++的前景
许多朋友都有这样的疑问,学习C/++能做什么?有什么好处?薪资怎么样,下面就为大家来解答! 像前面的文章有提到过,计算机专业位列热门专业第一门,可想前景如何.C语言C++属于高级语言,适合人类编写,现 ...