首页 > 代码库 > BZOJ3996[TJOI2015]线性代数

BZOJ3996[TJOI2015]线性代数

Description

给出一个N*N的矩阵B和一个1*N的矩阵C。求出一个1*N的01矩阵A.使得

D=(A*B-C)*A^T最大。其中A^T为A的转置。输出D

Input

第一行输入一个整数N,接下来N行输入B矩阵,第i行第J个数字代表Bij.
接下来一行输入N个整数,代表矩阵C。矩阵B和矩阵C中每个数字都是不超过1000的非负整数。 

Output

输出最大的D

Sample Input

3
1 2 1
3 1 0
1 2 3
2 3 7

Sample Output

2

HINT

1<=N<=500

 

题解:

这题包装得可真好啊……

D=A*B*A^T-C*A^T

假如A的第i项为1,则D会减去C[1,i]。

假如A的第i项、第j项都为1,则D会加上B[i,j]。

这样,题目就变成了类似于BZOJ1497[NOI2006]最大获利的模型:n个物品,取某个物品会有代价,若同时取某两个物品则会有收益。

题目变成了最大权闭合子图问题,用DINIC网络流求最小割求解。

 

代码:

技术分享
const
  inf=100000000;
type
  rec=record
    s,e,w,flow,next:longint;
  end;
var
  b,bb,d,q:array[0..2002002] of longint;
  a:array[-1..2002000] of rec;
  v:array[0..2002000] of boolean;
  n,m,i,j,k,l,st,ed,ww,top,tar,ans,x:longint;
function min(aa,bb:longint):longint;
begin
  if aa<bb then exit(aa);exit(bb);
end;
procedure add(st,ed,ww:longint);
begin
  inc(top);
  a[top].s:=st;
  a[top].e:=ed;
  a[top].w:=ww;
  a[top].next:=b[st];
  b[st]:=top;
end;
function bfs:boolean;
var head,tail,x,u:longint;
  y:rec;
begin
  fillchar(v,sizeof(v),false);
  tail:=1; head:=0; d[st]:=1;
  v[st]:=true; q[1]:=st;
  while head<tail do
  begin
    inc(head); x:=q[head];
    u:=b[x];
    while u>0 do
    begin
      y:=a[u];
      if(not v[y.e])and(y.flow<y.w)then
      begin
        v[y.e]:=true;
        d[y.e]:=d[x]+1;
        inc(tail); q[tail]:=y.e;
      end;
      u:=y.next;
    end;
  end;
  exit(v[tar]);
end;
function addflow(p,maxflow:longint):longint;
var
  o:longint;
  y:rec;
begin
  if(p=tar)or(maxflow=0)then exit(maxflow);
  addflow:=0;
  while bb[p]>0 do
  begin
    y:=a[bb[p]];
    if(d[y.e]=d[p]+1)and(y.flow<y.w)then
    begin
      o:=addflow(y.e,min(maxflow,y.w-y.flow));
      if o>0 then
      begin
        inc(a[bb[p]].flow,o);
        dec(a[bb[p] xor 1].flow,o);
        dec(maxflow,o);
        inc(addflow,o);
        if maxflow=0 then break;
      end;
    end;
    bb[p]:=y.next;
  end;
end;
function network:longint;
begin
  network:=0;
  while bfs do
  begin
    for i:=st to tar do bb[i]:=b[i];
    inc(network,addflow(st,inf));
  end;
end;
begin
  readln(n); st:=0;
  top:=1; tar:=n;
  for i:=1 to n do
  for j:=1 to n do
  begin
    read(x);
    if x>0 then
    begin
      inc(tar);
      add(st,tar,x);
      add(tar,st,0);
      add(tar,i,inf);
      add(i,tar,0);
      add(tar,j,inf);
      add(j,tar,0);
      ans:=ans+x;
    end;
  end;
  inc(tar);
  for i:=1 to n do
  begin
    read(j);
    add(i,tar,j);
    add(tar,i,0);
  end;
  writeln(ans-network);
end.
View Code

BZOJ3996[TJOI2015]线性代数