bzoj 2150 最小不相交路徑覆蓋
阿新 • • 發佈:2018-12-31
題意:n*m的矩陣,有一些是障礙點不能經過。約定:(1)可以從任意非障礙點出發或停留在任意非障礙點,能且只能往下走,不能忘往回走且不能經過障礙點(2)每個城鎮要求過且只能過一次(3)每次只能走r*c的路線 要求:在滿足所有約定的條件下,用最少的軍隊經過矩陣上所有非障礙點,輸出最少軍隊數
對於約定我們逐條分析:
(1)“只能往下走且不能回走且不能經過障礙點","每次只能走r*c的路線” 要求我們的建邊是有向邊且出發點和到達點都是非障礙點,二者滿足 abs(x1-x2)+abs(y1-y2)=r*c,且不會出現環的情況
(2)“過且只能過一次” 要求路徑不相交 或 用網路流限流
(3)所求:在圖中找一些路徑,如果把這些路徑中的每條路徑從它的起始點走到它的終點,那麼恰好可以經過圖中的每個非障礙點一次且僅一次。求最少路徑數
綜上,我們最終建好的圖是DAG,而我們的所求恰好為最小不相交路徑覆蓋(一些路徑使之覆蓋了圖中的所有非障礙點,且任何一個頂點有且只有一條路徑與之關聯,這些路徑互不相交)
裸上模板即可
——by Eirlysvar 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.