最大流:基礎

來源:互聯網
上載者:User

前幾個月第一次模仿別人的C代碼半懂不懂得寫了一次裸的最大流:RQNOJ 194:學生運輸,演算法導論上太多定義、分析、證明了,剛開始看得不是很明白,相比之下資料結構與演算法分析有圖解,但是沒有給出代碼。

後來才知道自己寫的BFS增廣是叫Edmonds-Karp演算法,屬於Ford-Fulkerson方法,效率是比DFS增廣好些,但是也就只能對付RQ上的弱資料,碰到強題還是不行。

最近興緻突發想學習網路流,想學一下dinic,看王欣上的課件模模糊糊有些懂了,但是沒有找到適合模仿的代碼。

之後找到一份比較全的網路流資料,不但有dinic的分析還有SAP的課件和代碼。然後看到zkw的SAP演算法心得上講“事實上,SAP演算法更易於理解,時間效率更高,編程更簡單,思路更清晰。”,給出的用SAP做USACO中的ditch的代碼比我的EK都短,然後就背叛dinic了轉去學SAP了。

SAP有當前弧和GAP最佳化,目前沒有嘗試過當前弧。

早上做NOI2006最大獲利,思路很巧妙,黑書P317有幾乎一樣的題目的分析。具體的涉及最大閉權子圖什麼的,自己目前沒有能力獨立想出來,暫時先放一下吧。

我的RQNOJ194代碼:

var  a:array[1..1000,1..1000] of longint;  q,prev,low:array[1..100000] of longint;  m,n,max:longint;procedure init;var  i,j,x,y,z:longint;begin  readln(m,n);  for i:=1 to m do  begin    read(x,y,z);    a[x,y]:=z;  end;end;procedure max_flow;var  i,j,k,x,head,tail,s,t:longint;begin  while true do  begin    fillchar(low,sizeof(low),0);   // fillchar(prev,sizeof(prev),0); I don't konw why can't=0 and change  (prev[i]<0)to<>0?    for i:=1 to n do     prev[i]:=-1;    head:=1;    tail:=1;    q[head]:=1;    s:=1;    t:=n;    low[1]:=maxint;    while head<=tail do    begin      x:=q[head];      inc(head);      for i:=1 to n do        if (a[x,i]>0)and(prev[i]<0) then        begin          inc(tail);          q[tail]:=i;          if low[x]<a[x,i] then            low[i]:=low[x]          else low[i]:=a[x,i];          prev[i]:=x;        end;      if prev[t]>0 then break;    end;    if prev[t]>0 then    begin      x:=t;      inc(max,low[t]);      while x<>s do      begin        a[x,prev[x]]:=a[x,prev[x]]+low[t];        a[prev[x],x]:=a[prev[x],x]-low[t];        x:=prev[x];      end;    end else break;  end;end;procedure print;begin  writeln(max);end;//=============main=================begin  init;  max_flow;  print;end.

我的最大獲利代碼(80分)

const  oo=19930508;//?var  vh,h,g,benefit,cost,e,c,opp,next:array[0..400000] of longint;  augc,s,t,i,j,k,m,n:longint;  flow,tmp,size,x,y,z,tot:longint;  found:boolean;procedure addedge(x,y,z:longint);begin  inc(size); e[size]:=y; next[size]:=g[x];  g[x]:=size; opp[size]:=size+1;  c[size]:=z;  inc(size); e[size]:=x; next[size]:=g[y];  g[y]:=size; opp[size]:=size-1;  c[size]:=0;end;procedure init;begin  readln(n,m);        //m:user n:station  for i:=1 to n do    read(cost[i]);  for i:=1 to m do  begin    readln(x,y,benefit[i]);    addedge(i,m+x,oo);    addedge(i,m+y,oo);  end;  s:=0;        //s:0 t:n+m+1 1..m:user m+1..m+n:station  t:=m+n+1;  tot:=t+1;  for i:=1 to n do    addedge(m+i,t,cost[i]);  for i:=1 to m do    addedge(s,i,benefit[i]);end;procedure sap(m:longint);var  minh,p,augco,i:longint;begin  minh:=tot-1;  augco:=augc; //backup now augc  if m=t then  begin    found:=true;    inc(flow,augc);    exit;      //found  end;  p:=g[m];  while p>0 do  begin    i:=e[p];    if c[p]>0 then    begin      if h[i]+1=h[m] then//can      begin        if c[p]<augc then          augc:=c[p];        sap(i);         //dfs        if h[s]>=tot then exit; //no way        if found then break;  //found        augc:=augco;          //recover the augc      end;      if h[i]<minh then minh:=h[i];//adjustment    end;    p:=next[p];  end;  if not found then  begin    dec(vh[h[m]]);       //gap    if vh[h[m]]=0 then h[s]:=tot;    h[m]:=minh+1;    inc(vh[h[m]]);  end  else begin    dec(c[p],augc);    inc(c[opp[p]],augc);  end;end;procedure main;begin  vh[0]:=tot;  while h[0]<tot do  begin    augc:=oo;    found:=false;    sap(0);  end;end;procedure print;begin  for i:=1 to m do    inc(tmp,benefit[i]);  writeln(tmp-flow);end;begin  assign(input,'profit.in');  reset(input);  assign(output,'profit.out');  rewrite(output);  init;  main;  print;  close(output);  close(input);end.

因為是模仿別人的,很不理解為什麼總節點數是t+1,其實是源點設成0了。增廣的過程少打了一個局部變數,DEBUG了一個多小時。很疑惑為什麼這個程式能過所有點(不過他資料範圍似乎開小了),我和他程式的區別是:我用一個found函數記錄有沒有找到增廣路,而他則是根據返回的增光路流量是不是為0。根據他的程式我改了一下,能AC:

const  oo=19930508;//?var  vh,h,g,benefit,cost,e,c,opp,next:array[0..400000] of longint;  augc,s,t,i,j,k,m,n:longint;  flow,tmp,size,x,y,z,tot:longint;  found:boolean;procedure addedge(x,y,z:longint);begin  inc(size); e[size]:=y; next[size]:=g[x];  g[x]:=size; opp[size]:=size+1;  c[size]:=z;  inc(size); e[size]:=x; next[size]:=g[y];  g[y]:=size; opp[size]:=size-1;  c[size]:=0;end;procedure init;begin  readln(n,m);        //m:user n:station  for i:=1 to n do    read(cost[i]);  for i:=1 to m do  begin    readln(x,y,benefit[i]);    addedge(i,m+x,oo);    addedge(i,m+y,oo);  end;  s:=0;        //s:0 t:n+m+1 1..m:user m+1..m+n:station  t:=m+n+1;  tot:=t+1;  for i:=1 to n do    addedge(m+i,t,cost[i]);  for i:=1 to m do    addedge(s,i,benefit[i]);end;function sap(i,now:longint):longint;var  p,minh,tmp,j:longint;begin  minh:=tot-1;  sap:=0;  if i=t then  begin    inc(flow,now);    exit(now);  end;  p:=g[i];  while p>0 do  begin    j:=e[p];    if c[p]>0 then    begin      if h[j]+1=h[i] then      begin        if c[p]<now then tmp:=sap(j,c[p]) else tmp:=sap(j,now);        dec(now,tmp);        inc(sap,tmp);        dec(c[p],tmp);        inc(c[opp[p]],tmp);        if h[s]>=tot then exit;        if now=0 then break;      end;      if h[j]<minh then minh:=h[j];    end;    p:=next[p];  end;  if sap=0 then  begin    dec(vh[h[i]]);    if vh[h[i]]=0 then h[s]:=tot;    h[i]:=minh+1;    inc(vh[h[i]]);  end;end;    procedure work;begin  vh[0]:=tot;  while h[s]<tot do    sap(s,oo);end;procedure print;begin  for i:=1 to m do    inc(tmp,benefit[i]);  writeln(tmp-flow);end;begin  assign(input,'profit.in');  reset(input);  assign(output,'profit.out');  rewrite(output);  init;  work;  print;  close(output);  close(input);end.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.