首页 > 代码库 > 【Codevs1227】方格取数2(费用流)

【Codevs1227】方格取数2(费用流)

题意:给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)

现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,

这样一共走K次,现在要求K次所达到的方格的数的和最大。

n<=50,k<=10

思路:费用流

将每个点裂成一个出点和一个入点(i,j,1..2),这个思路与最大流类似

(i,j,1)->(i,j,2) 连两条边:

容量为1,费用为a[i,j]

容量为K,费用为0

(i,j,2)->(i+1,j,1)连容量为K,费用为0的边 (i,j+1)类似

(n,n,2)->T 连流量为K,费用为0的边限制流量

跑最大费用最大流就行了,其实就是SPFA的三角不等式改个方向

  1 var fan:array[1..200000]of longint;
  2     q:array[0..20000]of longint;
  3     head,vet,next,len1,len2:array[1..20000]of longint;
  4     pre:array[1..20000,1..2]of longint;
  5     inq:array[1..20000]of boolean;
  6     dis:array[1..20000]of longint;
  7     a:array[1..50,1..50]of longint;
  8     num:array[1..50,1..50,1..2]of longint;
  9     n,m,k1,i,j,k,tot,s,source,src:longint;
 10     ans:int64;
 11 
 12 function min(x,y:longint):longint;
 13 begin
 14  if x<y then exit(x);
 15  exit(y);
 16 end;
 17 
 18 procedure add(a,b,c,d:longint);
 19 begin
 20  inc(tot);
 21  next[tot]:=head[a];
 22  vet[tot]:=b;
 23  len1[tot]:=c;
 24  len2[tot]:=d;
 25  head[a]:=tot;
 26 
 27  inc(tot);
 28  next[tot]:=head[b];
 29  vet[tot]:=a;
 30  len1[tot]:=0;
 31  len2[tot]:=-d;
 32  head[b]:=tot;
 33 end;
 34 
 35 function spfa:boolean;
 36 var u,t,w,i,e,v:longint;
 37 begin
 38  for i:=1 to s do
 39  begin
 40   dis[i]:=-maxlongint;
 41   inq[i]:=false;
 42  end;
 43  t:=0; w:=1; q[1]:=source; inq[source]:=true; dis[source]:=0;
 44  while t<w do
 45  begin
 46   inc(t); u:=q[t mod (s+5)];
 47   inq[u]:=false;
 48   e:=head[u];
 49   while e<>0 do
 50   begin
 51    v:=vet[e];
 52    if (len1[e]>0)and(dis[u]+len2[e]>dis[v]) then
 53    begin
 54     pre[v,1]:=u; pre[v,2]:=e;
 55     dis[v]:=dis[u]+len2[e];
 56     if not inq[v] then
 57     begin
 58      inc(w); q[w mod (s+5)]:=v;
 59      inq[v]:=true;
 60     end;
 61    end;
 62    e:=next[e];
 63   end;
 64  end;
 65  if dis[src]=-maxlongint then exit(false)
 66   else exit(true);
 67 end;
 68 
 69 procedure mcf;
 70 var k,e:longint;
 71     t:int64;
 72 begin
 73  k:=src; t:=maxlongint;
 74  while k<>source do
 75  begin
 76   e:=pre[k,2]; k:=pre[k,1];
 77   t:=min(t,len1[e]);
 78  end;
 79  k:=src;
 80  while k<>source do
 81  begin
 82   e:=pre[k,2];
 83   len1[e]:=len1[e]-t;
 84   len1[fan[e]]:=len1[fan[e]]+t;
 85   ans:=ans+t*len2[e];
 86   k:=pre[k,1];
 87  end;
 88 end;
 89 
 90 begin
 91  assign(input,codevs1227.in); reset(input);
 92  assign(output,codevs1227.out); rewrite(output);
 93  readln(n,k1);
 94  for i:=1 to 200000 do
 95   if i mod 2=1 then fan[i]:=i+1
 96    else fan[i]:=i-1;
 97  for i:=1 to n do
 98   for j:=1 to n do read(a[i,j]);
 99  for i:=1 to n do
100   for j:=1 to n do
101    for k:=1 to 2 do
102    begin
103     inc(s); num[i,j,k]:=s;
104    end;
105  for i:=1 to n do
106   for j:=1 to n do
107   begin
108    add(num[i,j,1],num[i,j,2],1,a[i,j]);
109    add(num[i,j,1],num[i,j,2],k1,0);
110    if j+1<=n then add(num[i,j,2],num[i,j+1,1],k1,0);
111    if i+1<=n then add(num[i,j,2],num[i+1,j,1],k1,0);
112   end;
113  source:=1; src:=s+1; inc(s);
114  add(num[n,n,2],src,k1,0);
115  while spfa do mcf;
116  writeln(ans);
117  close(input);
118  close(output);
119 end.

 

【Codevs1227】方格取数2(费用流)