博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj1930
阅读量:7223 次
发布时间:2019-06-29

本文共 5061 字,大约阅读时间需要 16 分钟。

一开始我觉得这不是一个弱弱的费用流吗?

每个豆豆拆点,入点出点随便连连

由于肯定是DAG图,边权为正的最大费用肯定能增广出来

于是我们只要跑总流量为2的最大费用最大流不就行了吗

但是

这样会TLE,因为会出现稠密图,spfa跑稠密图太慢

既然这样,能不能换一个找增广路的方法呢?

最大路径更快的方法就是DAG图的拓扑排序+dp

但好像无法处理反向弧导致带来的环啊

那既然这样,反正总流量很小,

我们可以用DAG解决最大路径特有的dp找第一条增广路(因为这时候是肯定的DAG),跑出一个较大费用

然后再用spfa增广呢?这样就大大减小了时间复杂度

这就是AC方法

注意这道题空间卡的较紧,能开integer不要开longint

实现起来要小心

1 const mo=4010;  2 type node=record  3        next:longint;  4        point,flow,cost:integer;  5      end;  6   7 var edge:array[0..4100000] of node;  8     v:array[0..4010] of boolean;  9     d,rd,pre,pref:array[0..4010] of integer; 10     q:array[0..4010] of integer; 11     p,x,y,cur:array[0..4010] of longint; 12     len:longint; 13     max,s,t,i,j,n,m,be:integer; 14  15 procedure add(x,y,f,c:integer); 16   begin 17     edge[len].point:=y; 18     edge[len].flow:=f; 19     edge[len].cost:=c; 20     edge[len].next:=p[x]; 21     p[x]:=len; 22   end; 23  24 procedure preflow; 25   var x,y,f,r,i,j:longint; 26   begin 27     r:=1; 28     f:=1; 29     q[1]:=s; 30     while f<=r do  //拓扑排序 31     begin 32       x:=q[f]; 33       i:=p[x]; 34       while i<>-1 do 35       begin 36         y:=edge[i].point; 37         dec(rd[y]); 38         if (rd[y]=0) then 39         begin 40           inc(r); 41           q[r]:=y; 42         end; 43         i:=edge[i].next; 44       end; 45       inc(f); 46     end; 47     fillchar(d,sizeof(d),255); 48     d[s]:=0; 49     for j:=1 to r do //DAG图根据拓扑的顺序dp解决最大路径 50     begin 51       x:=q[j]; 52       i:=p[x]; 53       while i<>-1 do 54       begin 55         y:=edge[i].point; 56         if d[y]
d[max] then max:=y; 62         end; 63         i:=edge[i].next; 64       end; 65     end; 66   end; 67 68 procedure change;   //建立预处理后的网络继续增广 69   var i,j,e,w:longint; 70   begin 71     for i:=1 to n do 72       pref[i]:=1; 73     i:=max; 74     while i<>s do   //相当于找到第一条增广路然后弄一弄反向弧什么的 75     begin 76       pref[i]:=0; 77       j:=cur[i]; 78       dec(edge[j].flow); 79       if pre[i]=s then w:=i; 80       i:=pre[i]; 81     end; 82     len:=-1; 83     for i:=1 to n do 84       for j:=1 to n do 85         if (i<>j) then 86           if (x[i]<=x[j]) and (y[i]<=y[j]) then 87           begin 88             inc(len); 89             edge[len].point:=j+n; 90             inc(len); 91             add(j+n,i,1-edge[len-1].flow,0)  //添加原来没加的反向弧 92           end; 93 94     p[s]:=-1; 95     for i:=1 to n do   //下面很多处理的细节,不赘述,繁杂但不难想到 96     begin 97       if i=w then e:=0 else e:=1; 98       inc(len); 99       add(s,i+n,e,0);100       inc(len);101       add(i+n,s,1-e,0);102     end;103 //0 表示超级源点,s表示起点,t表示超级汇点104     t:=2*n+2;105     inc(len);106     add(0,s,1,0);107     inc(len);108     add(s,0,1,0);109     for i:=1 to n do   110     begin111       inc(len);112       add(i+n,i,pref[i],1);113       inc(len);114       add(i,i+n,1-pref[i],-1);115       if max=i then e:=0   116       else e:=1;117       inc(len);118       add(i,t,e,0);119       inc(len);120       add(t,i,1-e,0);121     end;122   end;123 124 function spfa:boolean;125   var f,r,x,y,i,j,head,tail:longint;126   begin127     fillchar(v,sizeof(v),false);128     for i:=0 to t do129       d[i]:=-mo;130     d[0]:=0;131     q[0]:=0;132     f:=0;133     r:=0;134     head:=1;135     tail:=1;136     while head<=tail do  //缩空间的写法,好久没这么写了137     begin138       x:=q[f];139       v[x]:=false;140       i:=p[x];141       while i<>-1 do142       begin143         y:=edge[i].point;144         if edge[i].flow>0 then145         begin146           if d[x]+edge[i].cost>d[y] then147           begin148             d[y]:=edge[i].cost+d[x];149             pre[y]:=x;150             cur[y]:=i;151             if not v[y] then152             begin153               v[y]:=true;154               r:=(r+1) mod mo;155               inc(tail);156               q[r]:=y;157             end;158           end;159         end;160         i:=edge[i].next;161       end;162       f:=(f+1) mod mo;163       inc(head);164     end;165     if d[t]=-mo then exit(false) else exit(true);166   end;167 168 function mincost:longint;  //最大费用最大流169   var i,j:longint;170   begin171     be:=d[max];172     mincost:=be;   //预处理出来的费用173     while spfa do174     begin175       mincost:=mincost+d[t];176       i:=t;177       while i<>0 do178       begin179         j:=cur[i];180         dec(edge[j].flow);181         inc(edge[j xor 1].flow);182         i:=pre[i];183       end;184     end;185   end;186 187 begin188   len:=-2;189   fillchar(p,sizeof(p),255);190   readln(n);191   for i:=1 to n do192     readln(x[i],y[i]);193   for i:=1 to n do194     for j:=1 to n do195       if (i<>j) then196         if (x[i]<=x[j]) and (y[i]<=y[j]) then197         begin198           len:=len+2;199           add(i,j,1,0);  //个人感觉这样建之后添加边更容易一点200           inc(rd[j]);201         end;202 203   s:=2*n+1;204   for i:=1 to n do205     if rd[i]=0 then206     begin207       len:=len+2;208       add(s,i,1,0);209       inc(rd[i]); 210     end;211 212   preflow;213   change;214   writeln(mincost);215 end.
View Code

 

转载于:https://www.cnblogs.com/phile/p/4473207.html

你可能感兴趣的文章
5月末周中国.COM总量净增1.2万个 美国净减2.6万个
查看>>
Elasticsearch数据建模-关联查询
查看>>
我的友情链接
查看>>
CentOS 下安装 Lnmp
查看>>
redis系列:通过日志案例学习string命令
查看>>
世界冠军之路:菜鸟车辆路径规划求解引擎研发历程
查看>>
Linux-sendmail
查看>>
关于BSTR的困惑
查看>>
什么时候使用HashMap?它有什么特点?
查看>>
框架名
查看>>
编译安装PHP
查看>>
插入透明背景Flash的HTML代码
查看>>
无标题
查看>>
我的友情链接
查看>>
Web前端入门学习(3)——CSS选择器
查看>>
DNS的搭建
查看>>
Apache/Nginx 访问日志分析脚本
查看>>
Curator的使用
查看>>
第五章 集合类型
查看>>
我的友情链接
查看>>