网络流(自行理解的Dinic)

自行理解的Dinic 注释即讲解

#include<bits/stdc++.h>
const int maxn=100008;
using namespace std;
int read()
{
    char ch=getchar();int f=1,w=0;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){w=w*10+ch-'0';ch=getchar();}
    return f*w;
}                            //读入优化

struct sj{
    int next;
    int to;
    int w;                    //w是剩余的流量
}a[maxn*2];            
int head[maxn],size=1;        //注意size 要赋值为1 否则会死循环
int m,n;
int s,t;
int cent[maxn];                //层数
int ans;

void add(int x,int y,int z)
{
    a[++size].to=y;
    a[size].next=head[x];
    head[x]=size;
    a[size].w=z;
}                            //加边

bool bfs()
{
    memset(cent,-1,sizeof(cent));        //cent 层数先清零
    queue <int> q;
    q.push(s);
    cent[s]=0;                            //起点进栈
    while(q.empty()!=1)
    {
        int ks=q.front();            
        q.pop();
        for(int i=head[ks];i;i=a[i].next)
        {
            int ts=a[i].to;
            if(cent[ts]==-1&&a[i].w>0)
            {
              q.push(ts);            
              cent[ts]=cent[ks]+1;        //层数加1
            }
        }
    }
    if(cent[t]<0)                        //如果已经找不到增广路
    return 0;
    return 1;
}

int dfs(int x,int low)                    //dfs搜索 参数:当前的点,当前最小的流量
{
    if(x==t)return low;                    //如果已经搜到终点了 就直接返回
    int flow=0,r;                        //避免重复流 每次都新定义一个统计的流量 每层都各自求和
    for(int i=head[x];i;i=a[i].next)
    {
        int st=a[i].to;
        if((a[i].w>0)&&(cent[st]==cent[x]+1))
        {
            r=dfs(st,min(a[i].w,low-flow));            //递归在这里  
            if(r>0)
            {
                a[i].w-=r;                            //当前增广路走过的边 残量减掉这么多
                a[i^1].w+=r;                        //反向边则加上这么多 
                flow+=r;                            //流量加上r 这次找已经流了这么多
            }
        }
    }
    return flow;                                    //递归返回时 则返回已经流完的流量
}


int main()                                //主函数
{
    n=read();m=read();
    s=read();t=read();
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        x=read();
        y=read();
        z=read();
        add(x,y,z);
        add(y,x,0);
    }                                    //建立反向边 
    while(bfs())
    {
        int row=dfs(s,0x3f3f3f);        //row代表这次搜索找到的流量总和
        ans+=row;
        cout<<row<<endl;
    }                                    //还能找到增广路
    cout<<ans;
    return 0;
}

 

posted @ 2017-12-24 21:52  Kevin_naticl  阅读(232)  评论(0编辑  收藏  举报