1. 程式人生 > >bzoj 2150 最小不相交路徑覆蓋

bzoj 2150 最小不相交路徑覆蓋

題意:n*m的矩陣,有一些是障礙點不能經過。約定:(1)可以從任意非障礙點出發或停留在任意非障礙點,能且只能往下走,不能忘往回走且不能經過障礙點(2)每個城鎮要求過且只能過一次(3)每次只能走r*c的路線    要求:在滿足所有約定的條件下,用最少的軍隊經過矩陣上所有非障礙點,輸出最少軍隊數

對於約定我們逐條分析:

(1)“只能往下走且不能回走且不能經過障礙點","每次只能走r*c的路線”   要求我們的建邊是有向邊出發點和到達點都是非障礙點,二者滿足 abs(x1-x2)+abs(y1-y2)=r*c,且不會出現環的情況

(2)“過且只能過一次” 要求路徑不相交 或 用網路流限流

(3)所求:在圖中找一些路徑,如果把這些路徑中的每條路徑從它的起始點走到它的終點,那麼恰好可以經過圖中的每個非障礙點一次且僅一次。求最少路徑數

綜上,我們最終建好的圖是DAG,而我們的所求恰好為最小不相交路徑覆蓋(一些路徑使之覆蓋了圖中的所有非障礙點,且任何一個頂點有且只有一條路徑與之關聯,這些路徑互不相交)

裸上模板即可

var
        n,m,r,c,ans,l   :longint;
        tx,ty           :longint;
        i,j,k           :longint;
        s               :string;
        way             :array[0..4,0..2] of longint;
        map             :array[0..55,0..55] of char;
        num             :array[0..55,0..55] of longint;
        vis             :array[0..2510] of boolean;
        last,link       :array[0..2510] of longint;
        pre,other       :array[0..11010] of longint;
procedure connect(x,y:longint);
begin
   inc(l);
   pre[l]:=last[x];
   last[x]:=l;
   other[l]:=y;
end;

function find(x:longint):boolean;
var
        p,q:longint;
begin
   q:=last[x];
   while (q<>0) do
   begin
      p:=other[q];
      if not vis[p] then
      begin
         vis[p]:=true;
         if (link[p]=0) or find(link[p]) then
         begin
            link[p]:=x; exit(true);
         end;
      end;
      q:=pre[q];
   end;
   exit(false);
end;

begin
   readln(n,m,r,c);
   for i:=1 to n do
   begin
      readln(s);
      for j:=1 to m do map[i,j]:=s[j];
   end;
   //
   ans:=0;
   for i:=1 to n do
     for j:=1 to m do if map[i,j]='.' then inc(ans);
   for i:=1 to n do
     for j:=1 to m do num[i,j]:=(i-1)*m+j;
   way[1,1]:=r; way[1,2]:=c;
   way[2,1]:=c; way[2,2]:=r;
   way[3,1]:=c; way[3,2]:=-r;
   way[4,1]:=r; way[4,2]:=-c;
   //
   for i:=1 to n do
     for j:=1 to m do
        if map[i,j]='.' then
        begin
           for k:=1 to 4 do
           begin
              tx:=i+way[k,1]; ty:=j+way[k,2];
              if (tx<=n) and (ty<=m) and (tx>0) and (ty>0) then
                if (map[tx,ty]='.') then connect(num[i,j],num[tx,ty]);
           end;
        end;
   //
   for i:=1 to n do
     for j:=1 to m do
       if map[i,j]='.' then
      begin
         fillchar(vis,sizeof(vis),false);
         if find(num[i,j]) then dec(ans);
     end;
   writeln(ans);
end.
——by Eirlys