【差分约束】Cashier Employment(出纳员的雇佣)Time Limit:1000MS Memory Limit:65536KTotal Submit:2 Accepted:2Description出纳员的雇佣(cashier.pas/c/cpp)【问题描述】Tehran的一家每天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)更多的出纳员在工作。
Input第一行为测试点个数(<= 20)。
每组测试数据的第一行为24个整数表示R(0),R(1),...,R(23)(R(I)<= 1000)。
接下来一行是N,表示申请者数目(0 <= N <= 1000),接下来每行包含一个整数tI (0 <= tI <= 23)。
两组测试数据之间没有空行。
Output对于每个测试点,输出只有一行,包含一个整数,表示需要出纳员的最少数目。
如果无解,你应当输出“No Solution”。
Sample Input11 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 152322110Sample Output1Hint本题数据不完整,请在本系统测试通过后到/problem?id=1275 提交完整测试!SourceTehran 2000解析1:题意: 一家24小时营业的超市,需要一批出纳员来满足它的需求,该超市在每天的不同时刻需要不同数目的出纳员来为顾客提供服务,现在给出一天里每一小时需要出纳员的最少数量……r[0],r[1],……r[23].r[0]表示从午夜到上午1:00需要出纳员的最少数目等等,每一天这些数据都是相同的,有n个人申请这项工作,每个申请者i在每天24小时中,从某一个特定的时刻开始连续工作恰好8小时,定义t[i(0<=t[i]<=23)为上面提到的开始时刻,也就是说,如果第i个申请者被录用,他将从t[i]时刻开始连续工作8小时.输入r[i]和t[i],计算为满足上述限制需要雇佣的最少出纳员数目.注意在每一时刻可以有比对应的r[i]更多的出纳员在工作.r[0……23]……每个时刻需要的出纳员数目t[0……23]……每个时刻应征的申请者数目求s[0……23]……s[i]表示0……i时刻雇佣的出纳员总数,s[i]-s[i-1]就是i时刻录用的出纳员数目,设s[-1]=0,sum为雇佣的所有出纳员总数,那么一个可行方案应该满足: s[i]-s[i-1]>=0 即在i时刻录用的出纳员数目大于或等于0s[i]-s[i-1]<=t[i] 即在i时刻录用的出纳员数目应该小于在i时刻申请者数目s[23]-s[-1]>=sums[i]-s[j]>=r[i] 此时i>j&&i=(j+8)%24 因为在0……j时刻雇佣的出纳员连续工作8个小时,此时i=j+8很显然需要重新雇佣出纳员且最小为r[i]s[j]-s[i]<=sum-r[i] 此时i<j&&i=(j+8)%24 因为j>i说明可能某一天雇佣的出纳员连续工作8个小时后到了下一天的i时刻,所以从i……j=16+i时刻需要雇佣的出纳员数目最大为sum-r[i]由于sum是未知的,所以可以根据上述约束条件来构造约束图,为方便建图,以0为起点,由于题目要求的是出纳员的最少数目,所以建图后用Bellman_Ford算法求解单源最长路,在这过程中枚举sum,如果途中不存在环且s[24]=sum,那么就找到了一个可行解.将约束条件整理如下:s[i]-s[i-1]>=0s[i-1]-s[i]>= -t[i] i=(1,2 (24)s[24]-s[0]>=sums[i]-s[j]>=r[i] i>j i=(j-1+8)%24+1s[i]-s[j]>=r[i]-sum i<j i=(j-1+8)%24+1Bellman_Ford算法求解最长路,在主程序中枚举sum,就可以得到需要雇佣的出纳员数目的最小值,也可以二分法求解.解析2:设num[ i ]为i时刻能够开始工作的人数,x[ i ]为实际雇佣的人数,设r[ i ]为i 时刻至少需要工作的人数,s[ I ]=x[ 1 ]+x[ 2 ]…+x[ I ]有如下关系:x[ I ]<=num[ I ]x[ I-7 ]+x[ I-6 ]+x[ I-5 ]+x[ I-4 ]+x[ I-3 ]+x[ I-2 ]+x[ I-1 ]+x[ I ]>=r[ I ]0<=s[ I ]-s[ I-1 ]<=num[ I ],1<=I<=24s[I]-s[ I-8 ]>=r[ I ], 8<=I<=24s[ I ]-s[ I+16 ]>=r[ I ]-sum,1<=I<=7s[0]=0s[24]-s[0]>=sum(冯威的论文少了这个条件,看了别人的解题报告,才发现。
想想也是,sum是枚举的当前最小值,s[24]是实际工作的工人,那么其一定大于sum)解析3:用s[i]表示从0时刻到i时刻雇的人的总数,t[i]是在i时刻来应聘的人,ans 为这一天雇佣的总人数,s[-1]=0,很容易得到两个约束:在i时刻的雇佣的人一定之能少于等于t[i],而且一定大于等于0(只是大于等于0,而不能说大于等于R[i] ,因为前面的时刻的人可以流下来到i时刻继续工作)。
就是一个人也不雇.0<=S[i]-s[i-1]<=t[i] => {s[i]-s[i-1] >=0 ; s[i-1]-s[i]>=-t[i]}最后一个小时雇的人肯定要大于等于ans,S[23]>=ans => s[23]-s[-1]>=ans;真正的8个小时的关系体现在这里:从j时刻雇佣的人工作到i时刻已经走了,那么在j+1时刻就必须雇佣大于等于R[i]个人 => s[i]-s[j]>=r[i] (i>j,i=(j+8)%24)&& s[i]-s[j]+ans>=r[i] (i<j,i=(j+8)%24)。
在这些不等式上面建立约束图,而ans事先不知道,先枚举。
如果存在正圈说明ans小了因为存在这样的路 w(0,8)=r[8] ,w(16,0)=r[0]-ans 中间的权时0 ,所以增大ans能避免正圈出现,也就是说如果ans=n的时候还出现正圈的话那么就无解了,二分就是根据这个单调关系写的但是没写出来….程序1:∙var k,sum,i,j,n,m,x,s:longint;∙ a:array[0..1000,1..3] of longint;∙ t,d,r:array[0..25] of longint;∙ can:boolean;∙∙procedure add(x,y,z:longint);∙begin∙ inc(s);∙ a[s,1]:=x; a[s,2]:=y; a[s,3]:=z;∙end;∙∙function Bellman_Ford:boolean;∙var i,j:longint;∙ flag:boolean;∙begin∙ for i:=1 to 24 do d[i]:=-1000000;∙ d[0]:=0;∙ for i:=0 to 24 do begin∙ flag:=true;∙ for j:=1 to s do∙ if d[a[j,2]]<d[a[j,1]]+a[j,3] then begin∙ d[a[j,2]]:=d[a[j,1]]+a[j,3]; flag:=false;∙ end;∙ if flag then break;∙ end;∙ for i:=1 to s do∙ if d[a[i,2]]<d[a[i,1]]+a[i,3] then exit(false);∙ if d[24]=sum then exit(true) else exit(false);∙end;∙∙begin∙ readln(n);∙ for k:=1 to n do begin∙ can:=true;∙ fillchar(a,sizeof(a),0);∙ for i:=1 to 24 do read(r[i]);∙ readln(m);∙ for i:=1 to m do begin∙ readln(x); inc(t[x+1]);∙ end;∙ for sum:=0 to m do begin∙ s:=0;∙ for i:=1 to 24 do begin∙ add(i-1,i,0);∙ add(i,i-1,-t[i]);∙ end;∙ for i:=8 to 24 do add(i-8,i,r[i]);∙ for i:=1 to 7 do add(i+16,i,r[i]-sum); ∙ add(0,24,sum);∙ if Bellman_Ford then begin∙ writeln(sum); can:=false; break;∙ end;∙ end;∙ if can then writeln('No Solution');∙ end;∙end.解析4:详细解释一下。
为避免负数,时间计数1~24。
令:R[i] i时间需要的人数(1<=i<=24)T[i] i时间应聘的人数(1<=i<=24)x[i] i时间录用的人数(0<=i<=24),其中令x[0]=0再设s[i]=x[0]+x[1]+……+x[i] (0<=i<=24),由题意,可得如下方程组:(1) s[i]-s[i-8]>=R[i] (8<=i<=24)(2) s[i]-s[16+i]>=R[i]-s[24] (1<=i<=7)(3) s[i]-s[i-1]>=0 (1<=i<=24)(4) s[i-1]-s[i]>=-T[i] (1<=i<=24)这个差分约束有个特殊的地方,(2)的右边有未知数s[24]。