bzoj3171

不难发现,每个点出度显然为1,要想整个图形成环,必然每个点的入度也为1;

所以,不难想到将每个点i拆成两个点i1,i2构成二分图,

连边s--->i1 流量为1,费用为0,i2--->t流量为1,费用为0

这样左右两边的点都只能匹配1次,也就满足了出入度为1;

对于点i的上下左右4个点,分别连i1--->j2,容量为1;

对于点i原来指向的点,之间边的费用为0,否则费用为1,表示要修改1次

然后最小费用最大流即可

注意这道题最左边的点超出边界后自动到达最右边的点

  1 const inf=10000007;
  2       dx:array[1..4] of integer=(-1,1,0,0);
  3       dy:array[1..4] of integer=(0,0,-1,1);
  4 
  5 type node=record
  6        flow,cost,point,next:longint;
  7      end;
  8 
  9 var edge:array[0..200100] of node;
 10     p,cur,pre,d:array[0..10010] of longint;
 11     q:array[0..20000] of longint;
 12     v:array[0..500] of boolean;
 13     num,kind:array[0..20,0..20] of longint;
 14     len,x,y,i,j,n,m,h,c,k,t:longint;
 15     s:string;
 16 
 17 procedure add(x,y,f,c:longint);
 18   begin
 19     inc(len);
 20     edge[len].point:=y;
 21     edge[len].flow:=f;
 22     edge[len].cost:=c;
 23     edge[len].next:=p[x];
 24     p[x]:=len;
 25   end;
 26 
 27 function spfa:boolean;
 28   var f,r,x,y:longint;
 29   begin
 30     q[1]:=0;
 31     f:=1;
 32     r:=1;
 33     for i:=1 to t do
 34       d[i]:=inf;
 35     d[0]:=0;
 36     fillchar(v,sizeof(v),false);
 37     v[0]:=true;
 38     while f<=r do
 39     begin
 40       x:=q[f];
 41       v[x]:=false;
 42       i:=p[x];
 43       while i<>-1 do
 44       begin
 45         y:=edge[i].point;
 46         if edge[i].flow>0 then
 47         begin
 48           if d[x]+edge[i].cost<d[y] then
 49           begin
 50             d[y]:=edge[i].cost+d[x];
 51             pre[y]:=x;
 52             cur[y]:=i;
 53             if not v[y] then
 54             begin
 55               v[y]:=true;
 56               inc(r);
 57               q[r]:=y;
 58             end;
 59           end;
 60         end;
 61         i:=edge[i].next;
 62       end;
 63       inc(f);
 64     end;
 65     if d[t]=inf then exit(false) else exit(true);
 66   end;
 67 
 68 function mincost:longint;
 69   var i,j:longint;
 70   begin
 71     mincost:=0;
 72     while spfa do
 73     begin
 74       i:=t;
 75       while i<>0 do
 76       begin
 77         j:=cur[i];
 78         dec(edge[j].flow);
 79         inc(edge[j xor 1].flow);
 80         i:=pre[i];
 81       end;
 82       mincost:=mincost+d[t];
 83     end;
 84   end;
 85 
 86 begin
 87   len:=-1;
 88   fillchar(p,sizeof(p),255);
 89   readln(n,m);
 90   for i:=1 to n do
 91   begin
 92     readln(s);
 93     for j:=1 to m do
 94     begin
 95       inc(h);
 96       num[i,j]:=h;
 97       if s[j]='U' then kind[i,j]:=1;
 98       if s[j]='D' then kind[i,j]:=2;
 99       if s[j]='L' then kind[i,j]:=3;
100       if s[j]='R' then kind[i,j]:=4;
101     end;
102   end;
103   t:=n*m*2+1;
104   for i:=1 to n do
105   begin
106     for j:=1 to m do
107     begin
108       add(0,num[i,j],1,0);
109       add(num[i,j],0,0,0);
110       add(num[i,j]+h,t,1,0);
111       add(t,num[i,j]+h,0,0);
112       for k:=1 to 4 do
113       begin
114         x:=i+dx[k];
115         y:=j+dy[k];
116         if x=0 then x:=n;
117         if x=n+1 then x:=1;
118         if y=0 then y:=m;
119         if y=m+1 then y:=1;
120         if kind[i,j]=k then c:=0 else c:=1;
121         add(num[i,j],num[x,y]+h,inf,c);
122         add(num[x,y]+h,num[i,j],0,-c);
123       end;
124     end;
125   end;
126   writeln(mincost);
127 end.
View Code
原文地址:https://www.cnblogs.com/phile/p/4473204.html