码迷,mamicode.com
首页 > 其他好文 > 详细

网络流

时间:2020-01-27 15:22:38      阅读:72      评论:0      收藏:0      [点我收藏+]

标签:pre   etc   include   删掉   onclick   span   c++   get   oid   

今天开始学网络流...

首先是bfs找通流的EK算法..

技术图片
#include<bits/stdc++.h>
using namespace std;
const int N=10010,M=100010,qwq=1<<30;
int link[N],tot=1,n,m,s,t,maxflow,vis[N],id,incf[N],pre[N];
struct edge{int y,v,next;}a[M<<1]; 
inline int read()
{
    int x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch==-) ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
}
inline void add(int x,int y,int v)
{
    a[++tot].y=y;
    a[tot].v=v;
    a[tot].next=link[x];
    link[x]=tot;
}
inline bool bfs()
{
    queue<int>q;q.push(s);
    id++;vis[s]=id;//标记源点 
    incf[s]=qwq;//初始化流量 
    while(q.size())
    {
        int x=q.front();q.pop();
        for(int i=link[x];i;i=a[i].next)
        {
            if(a[i].v)//如果当前的边有剩余流量 
            {
                int y=a[i].y;
                if(vis[y]==id) continue;//若已标记过,则退出. 
                incf[y]=min(incf[x],a[i].v);//更新最小剩余流量 
                pre[y]=i;//记录点的前驱(记录的是边) 
                q.push(y);vis[y]=id;//标记这个点 
                if(y==t) return true;//如果到达汇点,则返回true 
            }
        }
    }
    return false;
}
inline void update()
{
    int x=t;//从汇点出发. 
    while(x!=s)
    {
        int i=pre[x];//找到来时的边 
        a[i].v-=incf[t];//这条边剩余容量减少 
        a[i^1].v+=incf[t];//边的反向边剩余容量增加 
        x=a[i^1].y;//退回到上一个点 
    }
    maxflow+=incf[t];//最大流量更新. 
} 
int main()
{
    freopen("1.in","r",stdin); 
    n=read(),m=read(),s=read(),t=read();
    for(int i=1;i<=m;++i)
    {
        int x=read(),y=read(),v=read();
        add(x,y,v);add(y,x,0);//反向边的边权为0 
    }
    while(bfs()) update();
    printf("%d",maxflow);
    return 0;
}
View Code

 

 

之后就是优化的dfs剪枝找通流dinic算法(现在还是好迷得.....):

 

技术图片
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=10010,M=100010,qwq=1<<30;
int n,m,s,t,link[N],d[N],tot=1;
ll maxflow;
struct edge{int y,v,next;}a[M<<1];
inline int read()
{
    int x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch==-) ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
}
inline void add(int x,int y,int v)
{
    a[++tot].y=y;
    a[tot].v=v;
    a[tot].next=link[x];
    link[x]=tot;
}
inline bool bfs()
{
    queue<int>q;q.push(s);
    memset(d,0,sizeof(d));
    d[s]=1;//初始化s的深度. 
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=link[x];i;i=a[i].next)
        {
            int y=a[i].y;
            if(a[i].v&&!d[y])//如果当前边有剩余流量且还没有便利过 
            {
                q.push(y);
                d[y]=d[x]+1;
                if(y==t) return true;//这里忽略了其他深度比t大的点,但其实 
            }//已经构成了从s到t的残余网络. 
        }
    }
    return false;
}
inline int dinic(int x,int flow)
{
    if(x==t) return flow;
    int rest=flow,k;//rest表示flow与k的差值. 
    for(int i=link[x];i&&rest;i=a[i].next)//如果rest为0直接退出. 
    {
        int y=a[i].y;
        if(a[i].v&&d[y]==d[x]+1)
        {
            k=dinic(y,min(rest,a[i].v));//k表示当前找到的最小流量. 
            if(!k) d[y]=0;//如果k为0,直接将这个点删掉 
            a[i].v-=k;
            a[i^1].v+=k;//更新边权 
            rest-=k;//rest表示flow与k的差值 
         }
    }
    return flow-rest;
}
int main()
{
    freopen("1.in","r",stdin);
    n=read();m=read();s=read();t=read();
    for(int i=1;i<=m;++i)
    {
        int x=read(),y=read(),v=read();
        add(x,y,v);add(y,x,0);
    }
    int flow=0;
    while(bfs())//构建残余网络 
        while(flow=dinic(s,qwq)) maxflow+=flow;//累加剩余流量. 
    printf("%lld",maxflow);
    return 0; 
}
View Code

 

 

 

 


 

网络流

标签:pre   etc   include   删掉   onclick   span   c++   get   oid   

原文地址:https://www.cnblogs.com/gcfer/p/12235873.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!