雇佣收银员

Posted jjl0229

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了雇佣收银员相关的知识,希望对你有一定的参考价值。

链接

https://www.acwing.com/problem/content/395/

题目

一家超市要每天24小时营业,为了满足营业需求,需要雇佣一大批收银员。

已知不同时间段需要的收银员数量不同,为了能够雇佣尽可能少的人员,从而减少成本,这家超市的经理请你来帮忙出谋划策。

经理为你提供了一个各个时间段收银员最小需求数量的清单R(0),R(1),R(2),…,R(23)。

R(0)表示午夜00:00到凌晨01:00的最小需求数量,R(1)表示凌晨01:00到凌晨02:00的最小需求数量,以此类推。

一共有N个合格的申请人申请岗位,第 i 个申请人可以从ti时刻开始连续工作8小时。

收银员之间不存在替换,一定会完整地工作8小时,收银台的数量一定足够。

现在给定你收银员的需求清单,请你计算最少需要雇佣多少名收银员。

输入格式
第一行包含一个不超过20的整数,表示测试数据的组数。

对于每组测试数据,第一行包含24个整数,分别表示R(0),R(1),R(2),…,R(23)。

第二行包含整数N。

接下来N行,每行包含一个整数ti。

输出格式
每组数据输出一个结果,每个结果占一行。

如果没有满足需求的安排,输出“No Solution”。

数据范围
(0≤R(0)≤1000,)
(0≤N≤1000,)
(0≤t_i≤23)
输入样例:

1
1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
5
0
23
22
1
10

输出样例:

1

思路

(S_i)表示从1到i(方便起见把时间整体右移1h)一共雇佣的员工,那么需要满足一下要求:
(S_i-S-{i-1}≥0) 前缀和性质
(S_i-S_{i-1}≤t_i) 在i时最多可以雇佣的员工数((t_i)表示可以在这一时开始工作的员工数量)
(S_i-S_{i-8}≥r_i,(i≥8)) i时的员工不能少于顾客数
(S_i+S_{24}-S_{i+16}≥r_i,(i<8))
前三个等式都可以通过在两点间连边实现,第四个条件有三个变量。数据范围很小,可以通过从小到大枚举(S_{24})的值,表示(S_{24}=c),建一条从0到24边长为c的边和一条从24到0边长为-c的边,再跑spfa最长路判断是否有解。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=30,M=100;
int h[N],e[M],w[M],nex[M],idx;
int cnt[N],q[N],dis[N];
bool st[N];
int r[N],s[N];
void add(int u,int v,int c){
    e[idx]=v;
    w[idx]=c;
    nex[idx]=h[u];
    h[u]=idx++;
}
void build(int c){
    memset(h,-1,sizeof h);
    idx=0;
    for(int i=1;i<=24;++i){
        add(i-1,i,0);
    }
    for(int i=1;i<=24;++i){
        add(i,i-1,-s[i]);
    }
    for(int i=8;i<=24;++i){
        add(i-8,i,r[i]);
    }
    for(int i=1;i<8;++i){
        add(16+i,i,r[i]-c);
    }
    add(24,0,-c);
    add(0,24,c);
}
bool spfa(int c){
    build(c);
    memset(dis,-0x3f,sizeof dis);
    memset(cnt,0,sizeof cnt);
    memset(st,0,sizeof st);
    int hh=0,tt=0;
    q[tt++]=0;
    st[0]=1;
    dis[0]=0;
    while(hh!=tt){
        int u=q[hh++];
        if(hh==N)   hh=0;
        st[u]=0;
        for(int i=h[u];~i;i=nex[i]){
            int v=e[i];
            if(dis[v]<dis[u]+w[i]){
                dis[v]=dis[u]+w[i];
                cnt[v]=cnt[u]+1;
                if(cnt[v]>=24) return false;
                if(st[v]==0){
                    q[tt++]=v;
                    if(tt==N)  
                        tt=0;
                    st[v]=1;
                }
            }
        }
    }
    return true;
}
int main(){
    int T;
    cin>>T;
    while(T--){
        memset(s,0,sizeof s);
        for(int i=1;i<=24;++i){
            cin>>r[i];
        }
        int n;
        cin>>n;
        for(int i=1;i<=n;++i){
            int t;
            cin>>t;
            s[t+1]++;
        }
        bool f=0;
        for(int i=0;i<=1000;++i){
            if(spfa(i)){
                cout<<i<<endl;
                f=1;
                break;
            }
        }
        if(!f) cout<<"No Solution
";
    }
    system("pause");
    return 0;
}

以上是关于雇佣收银员的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 收银员不会自动创建订阅

Java 从入门到进阶之路

我怎样才能写出同月雇佣的员工和订单?

lot设备和收银台串口实现

C#简易商城收银系统v1.0(2-1)

超市收银系统