题意:(n+1)个点(编号为0~n),m条带权双向边,初始在0号点K个人,要求:(1)所有城市全部被经过(一个人经过即算被经过);(2)经过城市i前必须走完编号为编号为(0~i-1)的城市,且不能经过大于等于i的城市。在满足所有要求的前提下使得K个人走的总距离最小。
要求总距离最小,肯定是走满足条件下的两点最短距离,floyd预处理(注意floyd处理的时候k必须不超过i和j)
预处理完成后,再来考虑他们是怎么走的:
(1)在走完i号城市后,就不走了
(2)在走完i号城市后继续走(编号不一定连续,因为可能有其他人替他走了i+1号点)
增加源S和汇T,考虑满足题意的建图:
因为要求每个点都经过一次,所以把每个点拆成两个点i和i'
S -> 0 ' 容量为K 费用为0 【限流表示初始K个人】
i ->T 容量为1 费用为0 【第一次遍历完i城市】
S -> i' 容量为1 费用为0
i' -> j 容量为正无穷(可以走多次) 费用为dis[i,j]
能够发现,每一个点的第一次訪问都被转化成了一条从S出发的没有交叉的到汇的流,这样能够随意调整訪问顺序,保证了i訪问之前0~i-1都已经訪问过
var
n,m,k,l,ss,st :longint;
x,y,z,ans :longint;
i,j :longint;
vis :array[0..410] of boolean;
map :array[0..155,0..155] of longint;
que,dis,last :array[0..410] of longint;
pre,other,len,c :array[0..41010] of longint;
father :array[0..410] of longint;
function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;
procedure connect(x,y,z,cost:longint);
begin
inc(l);
pre[l]:=last[x];
last[x]:=l;
other[l]:=y;
len[l]:=z;
c[l]:=cost;
end;
function spfa:boolean;
var
h,tl,cur,p,q,i:longint;
begin
for i:=1 to st do dis[i]:=maxlongint div 10;
h:=0; tl:=1; que[1]:=ss; dis[ss]:=0;
while (h<>tl) do
begin
h:=h mod 405 +1;
cur:=que[h];
vis[cur]:=false;
q:=last[cur];
while (q<>0) do
begin
p:=other[q];
if (dis[p]>dis[cur]+c[q]) and (len[q]>0) then
begin
dis[p]:=dis[cur]+c[q];
father[p]:=q;
if not vis[p] then
begin
vis[p]:=true;
tl:=tl mod 405+1;
que[tl]:=p;
end;
end;
q:=pre[q];
end;
end;
if dis[st]=maxlongint div 10 then exit(false) else exit(true);
end;
procedure update;
var
low,cur:longint;
begin
low:=maxlongint div 10; cur:=st;
while (cur<>ss) do
begin
low:=min(low,len[father[cur]]);
cur:=other[father[cur] xor 1];
end;
cur:=st;
while (cur<>ss) do
begin
dec(len[father[cur]],low);
inc(len[father[cur] xor 1],low);
inc(ans,low*c[father[cur]]);
cur:=other[father[cur] xor 1];
end;
end;
procedure floyd;
var
i,j,k:longint;
begin
for k:=1 to n do
for i:=1 to n do
for j:=1 to n do
if ((k<=i) or (k<=j)) and (map[i,j]>map[i,k]+map[k,j]) then
map[i,j]:=map[i,k]+map[k,j];
end;
procedure build;
var
i,j:longint;
begin
connect(ss,1+n,k,0);
connect(n+1,ss,0,0);
for i:=2 to n do
begin
connect(ss,i+n,1,0);
connect(i+n,ss,0,0);
connect(i,st,1,0);
connect(st,i,0,0);
end;
for i:=1 to n do
for j:=i+1 to n do
if map[i,j]<>maxlongint div 10 then
begin
connect(n+i,j,maxlongint div 10,map[i,j]);
connect(j,n+i,0,-map[i,j]);
end;
end;
begin
read(n,m,k);
inc(n); ss:=2*n+1; st:=ss+1; l:=1;
for i:=1 to n do
for j:=1 to n do
if (i<>j) then map[i,j]:=maxlongint div 10;
for i:=1 to m do
begin
read(x,y,z);
inc(x); inc(y);
if z<map[x,y] then map[x,y]:=z;
map[y,x]:=map[x,y];
end;
floyd;
build;
ans:=0;
while spfa do update;
writeln(ans);
end.
——by Eirlys