POJ1275 Cashier Employment

时间:2019-06-18
本文章向大家介绍POJ1275 Cashier Employment,主要包括POJ1275 Cashier Employment使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Cashier Employment

Language:
Cashier Employment
Time Limit: 1000MSMemory Limit: 10000K
Total Submissions: 10117Accepted: 3895

Description

A supermarket in Tehran is open 24 hours a day every day and needs a number of cashiers to fit its need. The supermarket manager has hired you to help him, solve his problem. The problem is that the supermarket needs different number of cashiers at different times of each day (for example, a few cashiers after midnight, and many in the afternoon) to provide good service to its customers, and he wants to hire the least number of cashiers for this job.

The manager has provided you with the least number of cashiers needed for every one-hour slot of the day. This data is given as R(0), R(1), ..., R(23): R(0) represents the least number of cashiers needed from midnight to 1:00 A.M., R(1) shows this number for duration of 1:00 A.M. to 2:00 A.M., and so on. Note that these numbers are the same every day. There are N qualified applicants for this job. Each applicant i works non-stop once each 24 hours in a shift of exactly 8 hours starting from a specified hour, say ti (0 <= ti <= 23), exactly from the start of the hour mentioned. That is, if the ith applicant is hired, he/she will work starting from ti o'clock sharp for 8 hours. Cashiers do not replace one another and work exactly as scheduled, and there are enough cash registers and counters for those who are hired.

You are to write a program to read the R(i) 's for i=0..23 and ti 's for i=1..N that are all, non-negative integer numbers and compute the least number of cashiers needed to be employed to meet the mentioned constraints. Note that there can be more cashiers than the least number needed for a specific slot.

Input

The first line of input is the number of test cases for this problem (at most 20). Each test case starts with 24 integer numbers representing the R(0), R(1), ..., R(23) in one line (R(i) can be at most 1000). Then there is N, number of applicants in another line (0 <= N <= 1000), after which come N lines each containing one ti (0 <= ti <= 23). There are no blank lines between test cases.

Output

For each test case, the output should be written in one line, which is the least number of cashiers needed.
If there is no solution for the test case, you should write No Solution for that case.

Sample Input

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

Sample Output

1

Source

给出24个数,第i个数表示在(i,i+1)小时内需要的人数,之后m个数,代表m个人前来应聘,其中每个人工作连续的8小时,给出应聘的人开始工作的时间,问最少需要雇佣的人数(可以在某个时间段中人数多于需要的人数)

题解

参照刀刀狗0102的题解。

问题分析:因为二十四小时是循环的,所以这是一个环,这题不能只用前缀和表示关系。解决办法是枚举(二分)答案,然后连特殊边(边权根据枚举的答案变化)解决问题。

差分约束:

  1. 题目需要求什么,就找什么之间的关系(二项式),比如,题目求雇佣的人数,就找出雇佣人数之间的关系,s[i]代表从0到i一共雇佣的人数
  2. 注意0的问题,和总和的问题。
  3. 判断的问题,不能存在环,和不能违背要求的值

那么归结关系有
s[i]:1到i时刻雇佣的总人数。
c[i]:i时刻;来应聘的人数。
r[i]:i时刻需要的人数。

设需要的人数为sum,即枚举的答案。

  1. 实际问题
    0 <= s[i] - s[i-1] <= h[i] ;
  2. 总数
    s[24] - s[0] >= sum
  3. 分类讨论约束
    s[i] - s[i-8] >= r[i] (i >= 8)
    sum - s[i+16] + s[i] >= r[i] (i < 8)

对上面的条件整理,然后求最短路,如果没有负环那么就有解。

#include<iostream>
#include<cstring>
#include<queue>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;rg char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
    for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
    return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std;

co int N=1e3+1;
int n,r[N],c[N],d[N],s[N];
int head[N],edge[N],next[N],leng[N],tot;
bool v[N];

il void add(int x,int y,int z){
    edge[++tot]=y,leng[tot]=z,next[tot]=head[x],head[x]=tot;
}
int spfa(int now){
    for(int i=1;i<=7;++i) leng[head[i]]=now-r[i];
    leng[head[24]]=-now;
    memset(d,0x3f,sizeof d);
    memset(s,0,sizeof s);
    queue<int> q;
    for(int i=0;i<=24;++i) q.push(i),d[i]=0,v[i]=1;
    while(q.size()){
        int x=q.front();q.pop();
        v[x]=0;
        for(int i=head[x];i;i=next[i]){
            int y=edge[i],z=leng[i];
            if(d[y]>d[x]+z){
                d[y]=d[x]+z,s[y]=s[x]+1;
                if(s[y]>25) return 0;
                if(!v[y]) q.push(y),v[y]=1;
            }
        }
    }
    return 1;
}
void Cashier_Employment(){
    for(int i=1;i<=24;++i) read(r[i]);
    read(n),memset(c,0,sizeof c);
    for(int i=1;i<=n;++i) ++c[read<int>()+1];
    tot=0,memset(head,0,sizeof head);
    for(int i=1;i<=24;++i){
        add(i-1,i,c[i]);
        add(i,i-1,0);
    }
    for(int i=8;i<=24;++i) add(i,i-8,-r[i]);
    for(int i=1;i<=7;++i) add(i,i+16,0); // changeable length
    add(24,0,0);
    for(int i=1;i<=n;++i)
        if(spfa(i)) return printf("%d\n",i),void();
    puts("No Solution");
}
int main(){
    for(int t=read<int>();t--;) Cashier_Employment();
    return 0;
}

原文地址:https://www.cnblogs.com/autoint/p/11045256.html