8/23 网络流最大流+hungary算法

Posted 钟钟终

tags:

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

网络流、最大流

源点S和汇点T,每条有向边的有一个权值,成为边的容量c(x,y);若(x,y)不属于E,则c(x,y)=0;
f(x,y)表示边(x,y)上的流量,c(x,y)-f(x,y)称为边的剩余容量;
最大流:从源点流向汇点的最大流量
增广路:一条从源点到汇点的所有变得剩余容量>=0得路径
残留网:由网络中所有节点和剩余容量大于0的变构成的子图;
构建反向边的目的是提供一个"退流管道",提供了"后悔机制"

P3376 【模板】网络最大流

EK()算法,复杂度为O(nmm),一般可达:n=1000,m=10000,实际所用更小

借用大佬图片: 算法流程如下

#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+7;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
struct edge

    int to,c,nxt;
e[N];
int n,m,s,t;
int head[N],idx=1;
int mf[N],pre[N];
void add(int a,int b,int c)

    e[++idx]=b,c,head[a];
    head[a]=idx;

bool bfs()

    for(int i=0;i<=n;i++)
        mf[i]=0;
    queue<int>q;
    q.push(s);
    mf[s]=inf;
    while(q.size())
    
        int u=q.front();q.pop();
        for(int i=head[u];i;i=e[i].nxt)
        
            int v=e[i].to;
            if(mf[v]==0&&e[i].c)
            
                mf[v]=min(mf[u],e[i].c);
                pre[v]=i;
                q.push(v);
                if(v==t) return 1;
            
        
    
    return 0;

int EK()

    int flow=0;
    while(bfs())
    
        int v=t;
        while(v!=s)
        
            int i=pre[v];
            e[i].c-=mf[t];
            e[i^1].c+=mf[t];
            v=e[i^1].to;
        
        flow+=mf[t];
    
    return flow;

void solve()

    cin>>n>>m>>s>>t;
    for(int i=1,u,v,w;i<=m;i++)
    
        cin>>u>>v>>w;
        add(u,v,w);add(v,u,0);
    
    cout<<EK()<<endl;

signed main()

    //ios;
    //int T;cin>>T;
    //while(T--)
        solve();
    return 0;


P2740 [USACO4.2]草地排水Drainage Ditches

思路:从源点到汇点,在满足各条边可承受的容量条件下,可留过的最大流量是多少,采用EK()算算,构造残缺图
代码:

#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+7;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
struct edge

    int to,c,nxt;
e[N];
int n,m,s,t;
int head[N],idx=1;
int mf[N],pre[N];
void add(int a,int b,int c)

    e[++idx]=b,c,head[a];
    head[a]=idx;

bool bfs()

    for(int i=0;i<=n;i++)
        mf[i]=0;
    queue<int>q;
    q.push(s);
    mf[s]=inf;
    while(q.size())
    
        int u=q.front();q.pop();
        for(int i=head[u];i;i=e[i].nxt)
        
            int v=e[i].to;
            if(mf[v]==0&&e[i].c)
            
                mf[v]=min(mf[u],e[i].c);
                pre[v]=i;
                q.push(v);
                if(v==t) return 1;
            
        
    
    return 0;

int EK()

    int flow=0;
    while(bfs())
    
        int v=t;
        while(v!=s)
        
            int i=pre[v];
            e[i].c-=mf[t];
            e[i^1].c+=mf[t];
            v=e[i^1].to;
        
        flow+=mf[t];
    
    return flow;

void solve()

    cin>>n>>m;
    s=1,t=m;
    for(int i=1,u,v,w;i<=n;i++)
    
        cin>>u>>v>>w;
        add(u,v,w);add(v,u,0);
    
    cout<<EK()<<endl;

signed main()

    //ios;
    //int T;cin>>T;
    //while(T--)
        solve();
    return 0;


P1343 地震逃生

思路:
1.可套网络流模板。算出地震时在各个楼道可承受人数的条件下,求出最大逃生人数
2.再根据x总人数,算出可分的批次,答案为(x+ans-1)/x .算一道板子题
代码:

#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+7;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
struct edge

    int to,c,nxt;
e[N];
int n,m,s,t,x;
int head[N],idx=1;
int mf[N],pre[N];
void add(int a,int b,int c)

    e[++idx]=b,c,head[a];
    head[a]=idx;

bool bfs()

    for(int i=0;i<=n;i++)
        mf[i]=0;
    queue<int>q;
    q.push(s);
    mf[s]=inf;
    while(q.size())
    
        int u=q.front();q.pop();
        for(int i=head[u];i;i=e[i].nxt)
        
            int v=e[i].to;
            if(mf[v]==0&&e[i].c)
            
                mf[v]=min(mf[u],e[i].c);
                pre[v]=i;
                q.push(v);
                if(v==t) return 1;
            
        
    
    return 0;

int EK()

    int flow=0;
    while(bfs())
    
        int v=t;
        while(v!=s)
        
            int i=pre[v];
            e[i].c-=mf[t];
            e[i^1].c+=mf[t];
            v=e[i^1].to;
        
        flow+=mf[t];
    
    return flow;

void solve()

    cin>>n>>m>>x;
    s=1,t=n;
    for(int i=1,u,v,w;i<=m;i++)
    
        cin>>u>>v>>w;
        add(u,v,w);add(v,u,0);
    
    int ans=EK();
    if(ans==0)
    
        cout<<"Orz Ni Jinan Saint Cow!"<<endl;return;
    
    cout<<ans<<" "<<(x+ans-1)/ans<<endl;

signed main()

    //ios;
    //int T;cin>>T;
    //while(T--)
        solve();
    return 0;


P2763 试题库问题

思路:
1.采用二分图的思路。若所选类型的题目类型都可找到自身匹配的题目,即匹配数==cnt(要求题目数)
2.左部点为要求题目类型的数量,为虚点;右部点为具体的题目。二者连线,进行最大匹配

#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+7;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int k,n,head[N],idx,cnt,cnt2,num[25],tag[N];
int match[N],used[N],ans;
vector<int>v[N],res[N];
struct node

    int to,nxt;
e[N];
void add(int from,int to)

    e[++idx].to=to;
    e[idx].nxt=head[from];
    head[from]=idx;

int dfs(int u)

    for(int i=head[u];i;i=e[i].nxt)
    
        int v=e[i].to;
        if(!used[v])
        
            used[v]=1;
            if(match[v]==-1||dfs(match[v]))
            
                match[v]=u;
                return 1;
            
        
    
    return 0;

void hungary()

    memset(match,-1,sizeof(match));
    for(int i=1;i<=n;i++)
    
        memset(used,0,sizeof used);
        if(dfs(i))
            ans++;
    


void solve()

    cin>>k>>n;
    for(int i=1;i<=k;i++)
    
        cin>>num[i];
        cnt+=num[i];
    以上是关于8/23 网络流最大流+hungary算法的主要内容,如果未能解决你的问题,请参考以下文章

A Plug for UNIX UVA - 753(网络流)

网络流之最大流算法

最大流的EK算法模板

网络流最大流

模板网络最大流

网络最大流 dinic算法