• POJ 1275 Cashier Employment (差分约束+二分查找)


    Cashier Employment
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 6401   Accepted: 2312

    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小时营业的超市,需要一批出纳员来满足它的需求。超市经理雇佣你来帮他解决一个问题————超市在每天的不同时段需要不同数目的出纳员(例如,午夜只需一小批,而下午则需要很多)来为顾客提供优质服务,他希望雇佣最少数目的纳员。

    超市经历已经提供一天里每一小时需要出纳员的最少数量————R(0),R(1),...,R(23)。R(0)表示从午夜到凌晨1:00所需要出纳员的最少数目;R(1)表示凌晨1:00到2:00之间需要的;等等。每一天,这些数据都是相同的。有N人申请这项工作,每个申请者i在每天24小时当中,从一个特定的时刻开始连续工作恰好8小时。定义ti(0<=ti<=23)为上面提到的开始时刻,也就是说,如果第i个申请者被录用,他(或她)将从ti时刻开始连续工作8小时。

    试着编写一个程序,输入R(i),i=0,...,23,以及ti,i=1,...,N,它们都是非负整数,计算为满足上述限制需要雇佣的最少出纳员数目、在每一时刻可以有比对应R(i)更多的出纳员在工作
    输入描述:
    输入文件的第1行为一个整数T,表示输入文件中测试数据的数目(至多20个)。每个测试数据第一行为24个整数,表示R(0),R(1),...,R(23),R(i)最大可以取到1000。接下来一行是一个整数N,表示申请者的数目,0<=N<=1000。接下来有N行,每行为一个整数ti,0<=ti<=23,测试数据之间没有空行。
    输出描述:
    对输入文件中的每个测试数据,输出占一行,为需要雇佣的出纳员的最少数目。如果某个测试数据没有解。则输出"No Solution"。

    分析:由于题目给定的是某一时刻的信息,但是试图描述的却是某一时间段的信息,所以处理的时候将时间点转化为时间段。对于每一个时间段x(每一小时作为一个时间段处理)定义出一个变量 need[x] 表示从1到x时间段一共雇佣了多少员工。则对于题目中所描述的数据能够较好的构图,关键还能够解决雇佣多少人的问题,而如果采用 need[x] 表示x时段工作的员工的人数,虽然能够列出方程但不利于问题的求解。

    约定 need[x] 表示x时间段至少要有多少员工在,have[x] 表示x时段有多少人申请工作,lim表示欲招的员工个数。对于题目中给定的信息构图如下:
    0 <= need[x] - need[x-1] <= have[x];      // 雇佣的人数少于申请者但不能为负数
    need[x] - need[x-8] >= need[x]               // 当x>=8时,该方程成立,否则将出现负数显然不成立
    need[x-8+24] - need[i] <= lim - need[x]   // 当x<8时,由于昨天的雇人可以通宵上班,因此这个约束通过反面处理
    need[24] - need[0] >= lim                      // 最后24小时内雇佣人应该大于等于lim个人

    接下来就是求解什么了,我们要得到一天最少的雇佣人数即 need[24] - need[0] >= M中的M,因为M是一个变量,所以要求解M的最大值。将式子化为 need[0] - need[24] <= -M,M去最大,-M取最小,即求24到0的最短路,再比较 need[0] 是否等于-lim。最后就是要枚举lim,因为该模型只能够判定一个lim是否能够合法,而不能够一次求出最优解,由于最多有1000人,可以采用二分查找来枚举。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    
    using namespace std;
    
    const int VM=30;
    const int INF=0x3f3f3f3f;
    
    struct Edge{
        int to,nxt;
        int cap;
    }edge[2010];
    
    int n,cnt,head[VM],ans;
    int need[VM],have[VM],dis[VM],Count[VM],vis[VM];    //// 每个节点的dis[i]表示的含义为到第 i 个小时时间段已经雇佣的员工数量
      //need[i]表示 i 时间段一共雇佣了多少员工    have[i]表示 i 时段有多少人申请工作
    
    void addedge(int cu,int cv,int cw){
        edge[cnt].to=cv;    edge[cnt].cap=cw;   edge[cnt].nxt=head[cu];
        head[cu]=cnt++;
    }
    
    void build(int lim){    // lim表示欲招的员工个数
        cnt=0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=24;i++){
            addedge(i-1,i,have[i]);     // need[i] - need[i-1] <= hav[i], 雇佣的人数少于申请者
            addedge(i,i-1,0);           // need[i-1] - need[i] <= 0   即  need[i] - need[i-1] >= 0   每个小时内雇佣的人数应该是个非负数
        }   
        for(int i=1;i<8;i++)    // 由于无法直接得到从前一天的后几小时到当天前几小时的雇佣人数,所以反面求解
            addedge(i,24+i-8,lim-need[i]);  // need[24+i-8] - need[i] <= lim-need[i]
        for(int i=8;i<=24;i++)  // 前8小时内雇佣人数应该大于等于需求量
            addedge(i,i-8,-need[i]);    // need[i] - need[i-8] >= need[i] ,即:need[i-8]-need[i]<=-need[i]
        addedge(24,0,-lim); // need[24] - need[0] >= lim,即:need[0]-need[24]<=-lim  表示至少为lim个员工,这样就能够看在最好情况下能不能取到这个最小值
    }
    
    int SPFA(int lim){
        queue<int> q;
        while(!q.empty())
            q.pop();
        for(int i=0;i<VM;i++){
            dis[i]=INF;
            vis[i]=0;
            Count[i]=0;
        }
        dis[24]=0;  vis[24]=1;  Count[24]=1;
        q.push(24);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            if(Count[u]>25)
                return 0;
            vis[u]=0;
            for(int i=head[u];i!=-1;i=edge[i].nxt){
                int v=edge[i].to;
                if(dis[v]>dis[u]+edge[i].cap){
                    dis[v]=dis[u]+edge[i].cap;
                    if(!vis[v]){
                        vis[v]=1;
                        Count[v]++;
                        q.push(v);
                    }
                }
            }
        }
        return dis[0]=-lim;
    }
    
    int BinSearch(int l,int r){
        ans=-1;
        while(l<=r){
            int mid=(l+r)>>1;   // mid 表示一共能够雇佣的员工数量
            build(mid);
            if(SPFA(mid)){
                ans=mid;
                r=mid-1;    //因为此题要求的是最小的雇佣人数,所以得判断r=mid-1使否满足题意,使之越来越小
            }else
                l=mid+1;
        }
        return ans!=-1;
    }
    
    int main(){
    
        //freopen("input.txt","r",stdin);
    
        int t;
        scanf("%d",&t);
        while(t--){
            memset(have,0,sizeof(have));
            for(int i=1;i<=24;i++)  //0时刻申请将工作在第一个小时
                scanf("%d",&need[i]);
            scanf("%d",&n);
            int x;
            for(int i=0;i<n;i++){
                scanf("%d",&x);
                have[x+1]++;    //这样做是为了从1~24计算
            }
            if(BinSearch(0,n))
                printf("%d\n",ans);
            else
                printf("No Solution\n");
        }
        return 0;
    }
  • 相关阅读:
    Razor强类型视图下的文件上传
    Js Date对象
    Js用正则表达式验证字符串
    PLC软件: KW multiprog 和 codesys
    S7 200 下载程序块报错 "A compile error occurred , check non-fatal errors for more information " 大端模式
    WebOP Designer (在电脑上在线仿真)与 西门子 S7-200 PPI 通讯
    企业做iISO9001质量管理体系认证的步骤(通俗描述)
    .net framework 装不上的原因
    iso9001质量管理体系认证需要准备的材料&具体流程
    EPLAN 部件库中一个被容易遗漏的功能——“新变量”
  • 原文地址:https://www.cnblogs.com/jackge/p/3017790.html
Copyright © 2020-2023  润新知