网络流问题

Posted overrate-wsj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流问题相关的知识,希望对你有一定的参考价值。

网络流

网络流问题常见的求解目标有最大流(最小割)、最小费用最大流、上下界可行流等

 

最小割

最大流还有一个很重要的应用,就是求最小割,以下是一些定理,其实这些和二分图匹配里面的有点相似:

最小割 = 最大流

 

最大点权覆盖集 = 最小割

最小点权独立集 = 总权值 - 最大点权覆盖集

最小割的定义:把网络划分成两个集合,s,t使得在s集合和在t集合中的任意两点互相不相连,去掉的边就是割边,而这些割边代价总和就是割,最小割就是代价最小的划分方法

 

一类最小割的题目还是挺明显,如果是要把存在点划分两个集合,求最小代价之类的,就很明显是最小割了

最小割有一些挺经典的模型:

1、平面图求最小割:

这个做法就是,把平面每一部分面积当成点,然后相邻块连边,然后增设源点s和汇点t,分别在原来的入口出口的另一对角线上,和相应两部分边连边,这时候,每一个最小割,其实就是一个s到t的路径,那么求最短路就是最小割了

2、最小权闭合

这个做法是源点s连向正权值,负权值连向汇点t,之间关系连边容量INF,求出最小割之后,这个最小割就是最少损失,然后总权值 - 最小割得到的就是最大权闭合图的权值

关于最小割输出路径

根据题意,如果要s集合尽量多,就从t集合dfs,反之则从s集合dfs,不经过没有容量的边即可

费用流

一类K覆盖问题:

这类问题一般表现为,一个区间或者一些点,每个可以最多被覆盖k次,然后有一些特殊的边可以走,但是只能走一次,这时候要求k覆盖后的最大权值

其实就是费用流,建边把特殊边建起来,对应相应费用,然后其他边直接相连,费用为0,注意由于是要求最大代价,而算法是求最小费用,其实和KM匹配求最小一样的思路,把边权弄成负数,跑一下即可

网络流的一些特殊问题

上下界网络流:

无源无汇有上下界最大流:

这个要根据流量平衡来搞,建图先把边容量定成上限up - 下限down,然后每一个点,记录下流入流量和流出流量,然后设一个超级源s,超级汇t,s连接流量正的点,流量负的点连向t,然后跑最大流,跑完之后如果从s流出的流量都是满流,就是有解,每个边的真实流量就为当前边流量,加上原来的下限

有源有汇有上下界最大流:

建图方法一致,不过要多连上一条t->s容量为INF的边,这样跑一下最大流,t->s的流量就是答案

有源有汇有上下界最小流:

也是一样,不过t->s先不连,先求一次最大流,然后在连t->s,在做一次最大流把残余流量充分利用,然后t->s的流量就是答案

分层网络流:

这类题,以时间为单位,这样对于每个时间点就要建一层结点,时间上限不是很大的话,就可以每多一个时间点,就多一层结点,在原来的图上继续增广

混合图找欧拉回路:

欧拉回路入度等于出度,然后无向图先任意定向,然后记录每个点的度数和,度数和 / 2就是需要调整的边数,然后把源点连向正的,负的连向汇点,然后中间的边就是连无向边,因为只有无向边可以调整,然后跑一下最大流即可

增加哪些边会使得最大流增加:

这类问题其实就是对于满流的边,如果左边源点到他和他到汇点,能有一个残量网络,这条边就是可以增加的,利用两个dfs,分别从源点汇点出发即可

最大密度子图:

先要记录下每个结点的度数

利用二分搜索来搜索答案g,然后根据这个建图判断,判断的方式为:

源点与原图中每一个点连一条容量为m的边。原图中每一个点与汇点连一条容量为m+2*g-度数的边,再将原图中的无向边拆成两条有向边,容量都设为1.然后对此图求最大流,最后将(n*m-maxflow)/2 与0比较大小,如果它大于0,l = g,

否则r = g

 

POJ 3281 Dining

题意:

一个人有喜欢的饮料跟食物,现在给出这些关系,问最多能有多少人得到喜欢的饮料跟食物

思路:

网络流的题目往往难在建模,我们很容易想到的一种建模方法就是源点-食物-人-饮料-汇点

但是这样的话可能一个人可以满足多次,所以为了加上人的这个限制条件,就需要将人拆点,并连上一条权值为1的边

拆点也是对于点限制的很好的解决方法

技术图片
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
 using namespace std;
 const int inf=1<<30;
struct Graph{
    static const int M=100010,N=10010;
    int dis[N],cur[N],head[N],cnt;
    void Grap(){
        cnt=-1;
        memset(head,-1,sizeof head);
    }
    struct edge{
        int to,val,next;
    }e[M<<1];
    void _add(int u,int v,int val){
        cnt++;
        e[cnt].next=head[u];
        e[cnt].to=v;
        e[cnt].val=val;
        head[u]=cnt;
    }
    void add(int u,int v,int val){
        _add(u,v,val);
        _add(v,u,0);
    }
    bool bfs(int s,int t){
        queue<int> q;
        memset(dis,-1,sizeof dis);
        dis[s]=0;
        q.push(s);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=head[u];i!=-1;i=e[i].next){
                int v=e[i].to;
                if(dis[v]==-1&&e[i].val>0){
                    dis[v]=dis[u]+1;
                    q.push(v);
                }
            }
        }
        return dis[t]!=-1;
    }
    int dfs(int s,int t,int maxflow){
        if(s==t)return maxflow;
        int res=0;
        for(int& i=cur[s];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(dis[v]!=dis[s]+1||e[i].val<=0||res>=maxflow)continue;
            int f=dfs(v,t,min(e[i].val,maxflow-res));
            e[i].val-=f;
            e[i^1].val+=f;
            res+=f;
        }
        return res;
    }
    int Dinic(int s,int t){
        int ans=0;
        while(bfs(s,t)){
            memcpy(cur,head,sizeof head);
            ans+=dfs(s,t,inf);
        }
        return ans;
    }
}mode;
 int main()
 {
     mode.Grap();
     int n,a,b;
     scanf("%d%d%d",&n,&a,&b);
     for(int i=1;i<=n;i++){
         int f,d,x;
         scanf("%d%d",&f,&d);
         for(int j=1;j<=f;j++){
             scanf("%d",&x);
             mode.add(x,a+i,1);
         }
        for(int j=1;j<=d;j++){
            scanf("%d",&x);
            mode.add(a+n+i,2*n+a+x,1);
        }    
    }
    for(int i=1;i<=n;i++) mode.add(a+i,a+n+i,1);
    for(int i=1;i<=a;i++) mode.add(0,i,1);
    for(int i=1;i<=b;i++) mode.add(2*n+a+i,2*n+a+b+1,1);
    cout<<mode.Dinic(0,2*n+a+b+1)<<endl;
    return 0;
 }
View Code

 

以上是关于网络流问题的主要内容,如果未能解决你的问题,请参考以下文章

Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题

Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题

java缓冲字符字节输入输出流:java.io.BufferedReaderjava.io.BufferedWriterjava.io.BufferedInputStreamjava.io.(代码片段

使用FFmpeg转录网络直播流

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装