平均时间最短即总时间最短
首先不难想到,将每个工作人员拆成n个点
然后,我就卡住了,
的确,正向建图确实很难,因为我们不好表示在修第i个车之前,前面用了多少时间
于是我们应该逆向想一想,将这辆车作为某个工作人员倒数第k个修的车会对之后的时间做怎样的影响
显然,每个工作人员修车是相对独立的
也就是说,工作人员i倒数第k个修车j时对后续他修的车时间影响总和是time[i,j]*k
于是,每个工作人员拆成的n个点意义就明确了;
图就好建了;
当然,这是一个二分图,可以KM,可以最小费用最大流,
作为不会KM的弱渣,我就用最小费用最大流吧
const inf=;
type node=record
next,flow,cost,from,point:longint;
end;
var edge:array[..] of node;
q:array[..] of longint;
a:array[..,..] of longint;
pre,d,p:array[..] of longint;
v:array[..] of boolean;
ans,len,t,n,m,x,i,j,k:longint; procedure add(x,y,f,w:longint);
begin
inc(len);
edge[len].from:=x;
edge[len].point:=y;
edge[len].flow:=f;
edge[len].cost:=w;
edge[len].next:=p[x];
p[x]:=len;
end; function spfa:boolean;
var f,r,x,y,i:longint;
begin
for i:= to t do
d[i]:=inf;
d[]:=;
fillchar(v,sizeof(v),false);
v[]:=true;
f:=;
r:=;
q[]:=;
while f<=r do
begin
x:=q[f];
v[x]:=false;
i:=p[x];
while i<>- do
begin
y:=edge[i].point;
if edge[i].flow> then
begin
if d[y]>d[x]+edge[i].cost then
begin
d[y]:=d[x]+edge[i].cost;
pre[y]:=i;
if not v[y] then
begin
v[y]:=true;
inc(r);
q[r]:=y;
end;
end;
end;
i:=edge[i].next;
end;
inc(f);
end;
if d[t]>=inf then exit(false) else exit(true);
end; procedure mincost;
var i,j:longint;
begin
while spfa do
begin
i:=t;
while i<> do
begin
j:=pre[i];
dec(edge[j].flow);
inc(edge[j xor ].flow);
i:=edge[j].from;
end;
ans:=ans+d[t];
end;
end; begin
readln(m,n);
len:=-;
fillchar(p,sizeof(p),);
for i:= to n do
begin
for j:= to m do
read(a[i,j]);
readln;
end;
for i:= to n do
begin
add(,m*n+i,,);
add(m*n+i,,,);
end;
t:=m*n+n+;
for i:= to m do
begin
for j:= to n do
begin
add((j-)*m+i,t,,);
add(t,(j-)*m+i,,);
end;
for j:= to n do
for k:= to n do
begin
x:=a[j,i]*(n-k+);
add(j+m*n,i+(k-)*m,,x);
add(i+(k-)*m,j+m*n,,-x);
end;
end;
mincost;
writeln(ans/n::);
end.