题目链接:
<最大流有FF、EK、Dinic算法,最小费用流有SPFA、DIjkstra求解算法等,网络流在于建模,在此不在贴出代码>
P2756 飞行员配对方案问题
- 二分图最大匹配(匈牙利算法),看着模板一顿乱敲即可。
P4016 负载平衡问题
- 最小费用流
- 建模:源点s=0,汇点t=n+1,平均值ave(对于样例为12)
- 源点s向节点i(i的值s[i]>平均值ave)连边,花费0,容量s[i]-ave。
- 节点i(i的值s[i]>平均值ave)向节点j(j的值s[j]<平均值ave)连边,花费为节点i和j的顺逆中的最短距离,容量s[i]-ave。
- 节点j(j的值s[j]<平均值ave)向汇点连边,花费0,容量ave-s[j]。
P1251 餐巾计划问题
- 最小费用流
- 建模:源点s,汇点t,第i天为节点i。add_edge(from,to,cost,cap)。
- 对于节点i,每天都可以直接购买今天所需的餐巾数,连边:add_edge(s,i,p,num[i]) 。每天都需要num[i]数量的餐巾数,即保证每天向汇点t流入num[i]流量,连边:add_edge(i,t,0,num[i])。
- 节点i的餐巾可以经过快洗/慢洗送给节点i+m/i+n使用。这就表明了:
①从节点i流向节点i+m/i+n的容量必为num[i]。
②由于从源点s流向节点i的容量为num[i],而节点i流向节点i+m/i+n容量为num[i],流向汇点t的容量也为num[i],不满足一定可以向节点i+m/i+n流容量num[i]。
所以,对节点i进行拆点,拆为i和i+N,拆点之后直接从汇点s向i+N连边,不经过节点i。 - 源点s=0,汇点t=2*N+1。
源点s向节点i+n连边,容量为num[i],即:add_edge(s,i+N,0,num[i]),保证了条件2。
同时节点i的餐巾可以经过快洗/慢洗送给节点i+m/i+n使用,分别连边:add_edge(i+N,i+m,f,inf);add_edge(i+N,i+n,s,inf)。 - 节点i的餐巾只需送给第i+m/i+n个节点就好,然后分别在节点之间连边,add_edge(i,i+1,0,inf);表明今天剩余的餐巾可以留到下一天用。
// 建模代码:
int st=0,ed=2*N+1;
for(int i=1;i<=N;i++){
add_edge(st,i,p,num[i]);
add_edge(i,ed,0,num[i]);
add_edge(st,N+i,0,num[i]);
if(i+1<=N)add_edge(i,i+1,0,inf);
if(i+m<=N)add_edge(N+i,i+m,f,inf);
if(i+n<=N)add_edge(N+i,i+n,s,inf);
}
printf("%lld\n",min_cost_flow(st,ed));
P2761 软件补丁问题
- 最短路(说好的网络流24题呐!),状态用二进制压缩一下。
对于样例n=3,起点状态:111 终点为:000
对于状态u可以依次判断是否和1~m个补丁相容,进而进行状态转移。
P2762 太空飞行计划问题
- 感谢博主hiho问题的幽默阐述和博主Dilthey的结论证明,在此万分感谢~
- 最后一次BFS建立分层图中level[i]>0的点就是所求答案,因为从源点s出发的所能达到的点都在最大权闭合子图里,证明见Dilthey博客!
P3254 圆桌问题
- 最大流思路:二分图多重匹配,按照最大流建模即可。
- 贪心思路:依次把各单位分配给餐桌座位余量最大的餐桌,对于第一个单位的分配,各餐桌余量为餐桌容量;第二个单位的分配,先对各餐桌按座位余量sort一下,按从大到小给第二个单位分配,依次类推,中间不能分的时候,说明题目无解。贪心证明:不会~
P2763 试题库问题
- <思路同上题>最大流:源点s=0,汇点t=k+n+1。
- 类型节点1~k,题目节点 k+1~k+n。
- 源点到类型节点连边,容量为每个类型所需数;类型和相对应的题目连边,容量为1;题目和汇点连边,容量为1,跑一边最大流即可出锅。
P2770 航空路线问题
题意:即是求1~n的两条不相交路径,使得路径经过的点总数最多。
由于航线不能重叠,所以每个点只能经过一次(最后一个点和第一个点最多两次)。
- 最大费用最大流:源点s=1,汇点t=n+n。
- 每个点只能经过一次,即顶点有流量限制,这时候要拆点,控制流出流量为1,把节点i拆为节点i和节点i+n。
- 源点和汇点拆点(来回可经过两次,容量为2):add(i,i+n,0,2)。 其它点(只能经过一次,容量为1):add_edge(i,i+n,0,1)。
- 航线连边,西边城市i向东边城市j连边:add_edge(i+n,j,1,1)。航线连边,西边城市i向东边城市j连边:add_edge(i+n,j,1,1)。