HDU1529 Cashier Employment

Cashier Employment


Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 858 Accepted Submission(s): 367


Problem 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
Asia 2000, Tehran (Iran)

题意:Tehran 的一家每天 24 小时营业的超市,需要一批出纳员来满足它的需要。 超市经理雇佣你来帮他解决他的问题——超市在每天的不同时段需要不同数目 的出纳员(例如:午夜时只需一小批,而下午则需要很多)来为顾客提供优质 服务。他希望雇佣最少数目的出纳员。 经理已经提供你一天的每一小时需要出纳员的最少数量——R0, R1, ..., R23。R0 表示从午夜到上午 1:00 需要出纳员的最少数目,R1 表示上午 1:00 到 2:00 之间需要的,等等。每一天,这些数据都是相同的。有 N 人申请这项工作,每 个申请者 I 在没 24 小时中,从一个特定的时刻开始连续工作恰好 8 小时,定义 tI (0≤tI≤23)为上面提到的开始时刻。也就是说,如果第 I 个申请者被录取,他 (她)将从 tI 时刻开始连续工作 8 小时。 你将编写一个程序,输入 RI(I = 0..23)和 tI (I = 1..N) ,它们都是非负整 数,计算为满足上述限制需要雇佣的最少出纳员数目。在每一时刻可以有比对 应的 RI更多的出纳员在工作。

题意直接从IOI论文上复制下来的。

这题在IOI2001黄源河的论文上有讲,不看之前根本不知道怎么做。。

感觉这题超变态,就是按照论文上那几个公式(论文上后两个好像错了)。。。

0<=s[i]-s[i-1]<=w[i],w[i]是i这个时间可以开始工作的人的个数,这个很好理解,s[i]是0-i时刻工作的总人数。

s[i]-s[i-8]>=r[i],i>=8的情况,我这里把题目给出的时刻都加了1,所以这里的i就表示工作到i这个时刻结束,r[i]表示这个时刻需要需要的总人数,因为一个人能工作8小时,所以如果他在i-8这个时刻开始的工作,在i这个时刻他还在工作。

s[24]+s[i]-s[i+16]>=r[i],和上面一个差不多,i<8的情况,推一下就出来了。

上面的s[24]的值我们并不知道,但是要用差分约束做我们必须把他当做一个已知值,所以二分这个值然后建图,然后其实还有一个不等式,s[24]-s[0]=mid(mid是二分的值),可以把这个式子看成两个不等式,s[24]-s[0]>=mid和s[24]-s[0]<=mid,然后把后面那个换一下就是s[0]-s[24]>=-mid,然后从0往24跑最长路判环就好了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN=30;
const int MAXE=240;
const int INF=1<<30;
int head[MAXN],size;
struct EDGE
{
    int v,next;
    int dis;
}edge[MAXE];
void init()
{
    memset(head,-1,sizeof(head));
    size=0;
}
void add_edge(int u,int v,int dis)
{
    edge[size].v=v;
    edge[size].dis=dis;
    edge[size].next=head[u];
    head[u]=size++;
}
int dis[MAXN],cnt[MAXN];
bool vis[MAXN];
bool spfa(int s)
{
    memset(vis,0,sizeof(vis));
    memset(cnt,0,sizeof(cnt));
    for(int i=0;i<=24;i++)
        dis[i]=-INF;
    vis[s]=1;
    dis[s]=0;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v;
            if(dis[v]<dis[u]+edge[i].dis)
            {
                dis[v]=dis[u]+edge[i].dis;
                if(!vis[v])
                {
                    vis[v]=1;
                    cnt[v]++;
                    if(cnt[v]>24)
                        return 0;
                    q.push(v);
                }
            }
        }
    }
    return 1;
}
int w[MAXN],r[MAXN];
bool ok(int mid)
{
    init();
    for(int i=1;i<=24;i++)
    {
        add_edge(i-1,i,0);
        add_edge(i,i-1,-w[i]);
        if(i>=8)
            add_edge(i-8,i,r[i]);
        else
            add_edge(i+16,i,r[i]-mid);
    }
    add_edge(0,24,mid);
    add_edge(24,0,-mid);
    return spfa(0);
}
int main()
{
    int t,i,m,ll,rr,x;
    scanf("%d",&t);
    while(t--)
    {
        for(i=1;i<=24;i++)
            scanf("%d",&r[i]);
        scanf("%d",&m);
        memset(w,0,sizeof(w));
        for(i=1;i<=m;i++)
        {
            scanf("%d",&x);
            w[x+1]++;
        }
        ll=0,rr=m;
        int ans=-1;
        while(ll<=rr)
        {
            int mid=(ll+rr)>>1;
            if(ok(mid))
            {
                ans=mid;
                rr=mid-1;
            }
            else
                ll=mid+1;
        }
        if(ans==-1)
            printf("No Solution\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值