POJ 1275 Cashier Employment 差分约束

Cashier Employment

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 8506 Accepted: 3277

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

Tehran 2000

题意:
题意:德黑兰的一家每天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”。

参考:大佬的博客的差分的例题三
&&《算法艺术与信息学竞赛》

题解:
定义:
a[i]表示在i时刻开始工作的人数;
b[i]表示在i时刻工作人数的上限;(输入给出)
r[i]表示在i时刻最少需要工作的人数;(输入给出)
【PS:由于需要添加原点,而-1无法用数组存储,所以我们将时间全部+1,将工作时间变成1~24h。

对于i分为2种情况。
当i>=8时,a[i-7]+a[i-6]+…+a[i]>=r[i] //显然
当1<=i<=7时,即a[i+17]+a[i+18]+…+a[24]+—+a[1]+a[2]+…+a[i]>=r[i] //这一天还不到8个小时,就要算上前一天的工作人数,凑齐8个小时
且0<=a[i[<=b[i]
令T[i]表示a[i]的前缀和,则T[i]表示1~i时刻最少需要雇佣的出纳员的人数,则上面的不等式可以很容易地转化为:
1.i>=8时,T[i]-T[i-8]>=r[i]
2.1<=i<=7时,T[24]-T[i+16]+T[i]-T[0]>=r[i];
3.T[i]-T[i-1]>=0
4.T[i-1]-T[i]>=-b[i]

1、3、4都很好处理,重点考虑2。
由于T[0]显然是等于0的,所以原式可变为:
T[24]-T[i+16]+T[i]>=r[i]
T[i]-T[i+16]>=r[i]-T[24]。

而T[24]刚好就是我们所求的答案。
所以又有T[24]-T[0]=ans;
即T[24]-T[0]>=ans,T[0]-T[24]>=-ans;
我们可以枚举答案,再依次判断是否存在合法解,或者由于如果我们可以用x个出纳员满足要求,则肯定可以用x+1个出纳员满足要求,所以最后的答案满足递增性,我们可以用二分来查找这个答案。
如果不存在正环,则ans就是一组合法解(这里不用判断T[24]是否与ans一样是因为在建图时已经保证了这个要求,如果对于T[24]的处理只是将它建成T[24]-T[0]>=ans,则仍需要判断T[24]与ans是否一致)。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;

const int N = 26;
const int M = 10000 + 10;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int n;
int r[N],b[N];

struct node{
    int pre,v,w;
}e[M<<2];

int num=0,head[N],cur[N],tot;
void addedge(int from,int to,int w){
    e[++num].pre=head[from],e[num].v=to;
    head[from]=num,e[num].w=w;
}

deque<int> q;
int in[N],dis[N];
bool vis[N];
bool spfa(){
    memset(dis,-0x7,sizeof(dis));
    memset(in,0,sizeof(in));
    memset(vis,0,sizeof(vis));
    while(!q.empty()) q.pop_front();
    dis[0]=0,q.push_back(0);
    while(!q.empty()){
        int u=q.front();q.pop_front();vis[u]=false;
        for(int i=head[u];i;i=e[i].pre){
            int v=e[i].v;
            if(dis[v]<dis[u]+e[i].w){
                dis[v]=dis[u]+e[i].w;
                if(!q.empty()&&dis[v]>dis[q.front()]) q.push_front(v);
                else q.push_back(v);
                vis[v]=true;
                ++in[v];if(in[v]>25) return false;
            }
        }
    }
    return true;
}

bool check(int mid){
    memcpy(head,cur,sizeof(head)),num=tot;
    for(int i=1;i<=7;++i) addedge(16+i,i,r[i]-mid);
    addedge(0,24,mid);addedge(24,0,-mid);
    return spfa();
}

#define ms(x,y) memset(x,y,sizeof(x))
void update(){
    ms(head,0);num=0;ms(b,0);
}

int main(){
    int t=read();
    while(t--){
       update();
       for(int i=1;i<=24;++i) r[i]=read();
       n=read();
       for(int i=1;i<=n;++i){
           int x=read();++b[x+1];
       }
       for(int i=8;i<=24;++i) addedge(i-8,i,r[i]);
       for(int i=1;i<=24;++i) {addedge(i-1,i,0);addedge(i,i-1,-b[i]);}
       memcpy(cur,head,sizeof(cur));tot=num;
       int l=0,r=n,ans=-1;
       while(l<=r){
          int mid=l+r>>1;
          if(check(mid)) ans=mid,r=mid-1;
          else l=mid+1;
       }
       if(ans!=-1) printf("%d\n",ans);
       else printf("No Solution\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值