bzoj 1070 [SCOI2007]修车

Description

同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小。 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。

Input

第一行有两个m,n,表示技术人员数与顾客数。 接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人员维修第i辆车需要用的时间T。

Output

最小平均等待时间,答案精确到小数点后2位。

Sample Input

2 2
3 2
1 4

Sample Output

1.50

HINT

数据范围:
(2<=M<=9,1<=N<=60), (1<=T<=1000)

 

求平均费用这个有点无趣啊。。人数给定了其实只要求出最少的总时间花费就行了、、不用搞什么分数规划。

 

这题费用流的算法是很明显的啦、就是构图很巧妙~~

 

N辆车,M个工人。

 

把每个工人拆成N个点。记为A[i,j]表示第i个工人修倒数第j辆车。

每个车跟所有N*M个工人拆出的点连边。流量为1,费用为time[i,j]*k。

源和每辆车连边,N*M个点和汇连边,流量都为1,费用同为0。

 

为什么这么构图呢?

 

考虑第i个工人,他修第j辆车只对后面要修的车有影响,而前面修过的车已经对当前没有影响了。

而这个影响就是后面每个将要修理的车都多等待了time的时间。

 

其他边流量都为1是显然的,每辆车修一次,每个工人一个时段只能修理一辆车。

 

跑一遍费用流,出解、、

 

 

AC CODE

 

program bzoj_1070;

var line,capa,cost,next:array[1..66000] of longint;

    d,f,en,hs:array[1..610] of longint;

    time:array[1..60,1..9] of longint;

    sta,tt:array[1..610] of boolean;

    ans,tot,n,s,t,car:longint;

//============================================================================

procedure ins(x,y,z1,z2:longint);

begin

  inc(tot); line[tot]:=y;

  capa[tot]:=z1; cost[tot]:=z2;

  next[tot]:=en[x]; en[x]:=tot;

end;

//============================================================================

procedure init;

var i,j,k,m:longint;

begin

  readln(m,n); tot:=1;

  s:=n+m*n+1; t:=s+1;

  for i:=1 to n do

    for j:=1 to m do

      read(time[i,j]);

  for i:=1 to n do

  begin

    ins(s,i,1,0); ins(i,s,0,0);

    for j:=1 to m do

      for k:=1 to n do

      begin

        ins(i,j*n+k,1,k*time[i,j]);

        ins(j*n+k,i,0,-k*time[i,j]);

      end;

  end;

  for i:=1 to m do

    for j:=1 to n do

    begin

      ins(i*n+j,t,1,0);

      ins(t,i*n+j,0,0);

    end; car:=n; n:=t;

end;

//============================================================================

function dfs(u,flow:longint):longint;

var v,i,rest,tmp,l:longint;

begin

  if u=t then

  begin

    inc(ans,flow*d[u]);

    exit(flow);

  end;

  sta[u]:=false; tt[u]:=false;

  dfs:=0; i:=hs[u];

  while i<>0 do

  begin v:=line[i];

    if tt[v] then

    begin

      rest:=flow-dfs; l:=d[u]+cost[i]-d[v];;

      if capa[i]

      if (rest>0) and (l

      if (rest>0) and (l=0) then

      begin

        tmp:=dfs(v,rest); inc(dfs,tmp);

        dec(capa[i],tmp); inc(capa[i xor 1],tmp);

      end; if dfs=flow then break;

    end; i:=next[i]; hs[u]:=i;

  end; tt[u]:=true;

end;

//============================================================================

procedure zkw;

var flow,i,tmp:longint;

    ave:double;

begin

  ans:=0; flow:=0;

  for i:=1 to n do tt[i]:=true;

  for i:=1 to n do d[i]:=0;

  repeat

    for i:=1 to n do f[i]:=maxlongint;

    for i:=1 to n do sta[i]:=true;

    for i:=1 to n do hs[i]:=en[i];

    inc(flow,dfs(s,maxlongint));

    tmp:=maxlongint;

    for i:=1 to n do

      if sta[i] and (f[i]

    if tmp=maxlongint then break;

    for i:=1 to n do

      if sta[i] then inc(d[i],tmp);

  until false;

  ave:=ans/car; writeln(ave:0:2);

end;

//============================================================================

begin

  init;

  zkw;

end.

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值