本文主要是介绍poj 1275 Cashier Employment,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
题目链接:http://poj.org/problem?id=1275
Description
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
Output
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
题目大意:
德黑兰的一家每天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"。
这是《算法艺术与信息学竞赛》306页的原题,只不过是英文版。
在黑书上用的是最长路的算法 ,实际上最短路和最长路差不多的。
以下是黑书上的描述:
枚举sum,通过求最短路或最长路来求解,这是一种方法。
黑书中说的二分法是针对当s[-1]!=sum时,它与sum的关系来二分搜索的,这里就用代码描述了。
以上复制的 ,代码中的注释是根据自己的理解所解释的
#include<cstdio> #include<iostream> #include<queue>#define inf 0x3f3f3f3fusing namespace std;struct node {int to,w,next; }e[10000]; ///存图 前i个时刻需要人数 int r[25];///每个时刻出纳人员数 int t[25];///每个时刻申请人数 int dist[25];///最短距离 int head[25];///存图的起始点 int cnt,c[25];///记录个数和记录定点出现的次数// bool vis[25];///标记 ///初始化 void init() {cnt=0;for(int i=0;i<=24;i++){head[i]=-1;dist[i]=inf;vis[i]=false;c[i]=0;}dist[0]=0; }///建图 void add(int u,int v,int w)///w位u->v的值 u小于v {e[cnt].to=v;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt;cnt++; } void build(int root) {init();add(0,24,-root);///s[24]-s[0]>=root,s[0]<=s[24]-root///出纳人员的总人数for(int i=1;i<=24;i++){add(i-1,i,0);///s[i]-s[i-1]>=0,s[i-1]<=s[i]-0add(i,i-1,t[i]);///s[i]-s[i-1]<=t[i],s[i]<=s[i-1]+t[i]}for(int i=17;i<=24;i++){add(i,(i+8)%24,-r[(i+8)%24]+root);///s[i]-s[(i+8)%24]>=r[(i+8)%24]-s[24];s[(i+8)%24](小)<=s[i](大)-r[(i+8)%24]+s[24]///24>=i>=17}for(int i=1;i<=16;i++){add(i,i+8,-r[i+8]);///s[i+8]-s[i]>=r[i+8];s[i]<=s[i+8]-r[i+8]} }bool spfa(int root) {///spfa求单源最短路径queue<int >q;q.push(0);vis[0]=1;c[0]=1;while(!q.empty()){int u=q.front();q.pop();for(int i=head[u];i!=-1;i=e[i].next){int v=e[i].to;int w=e[i].w;if(dist[v]>dist[u]+w){dist[v]=dist[u]+w;if(!vis[v]){q.push(v);vis[v]=1;c[v]++;if(c[v]>24){return false;///负环}}}}vis[u]=0;}if(dist[24]==-root){return true;///root等于最后的数}return false; } int main() {int T;scanf("%d",&T);while(T--){for(int i=1;i<=24;i++){scanf("%d",&r[i]);t[i]=0;}int n,x;scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&x);t[x+1]++;}int f=0;for(int i=0;i<=n;i++){build(i);if(spfa(i)){printf("%d\n",i);f=1;break;}}if(!f)printf("No Solution\n");}return 0; }
这篇关于poj 1275 Cashier Employment的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!