【图】Dinic(n^2m)

struct Edge
{
	int from,to,cap,flow;
	
	void AddEdge(int from,int to,int cap)
	{
		edges.push_back((Edge){from,to,cap,0});
		edges.push_back((Edge){to,from,0,0}});
		m=edges.size();
		G[from].push_back(m-2);
		G[to].push_back(m-1);
	}
};

struct Dinic
{
	int n,m,s,t;
	vector<Edge> edges;
	vector<int> G[maxn];
	bool vis[maxn];
	int d[maxn];
	int cur[maxn];
	
	bool BFS()
	{
		memset(vis,0,sizeof(vis));
		queue<int> Q;
		Q.push(s);
		d[s]=0;
		vis[s]=1;
		while(!Q.empty())
		{
			int x=Q.front(); Q.pop();
			for(int i=0;i<G[x].size();i++)
			{
				Edge& e=edges[G[x][i]];
				if(!vis[e.to] && e.cap>e.flow)
				{
					vis[e.to]=1;
					d[e.to]=d[x]+1;
					Q.push(e.to);
				}
			}
		}
		return vis[t];
	}


	int DFS(int x,int a)
	{
		if(x==t || a==0)
			return a;
		int flow=0,f;
		for(int& i=cur[x];i<G[x].size();i++)
		{
			Edge& e=edges[G[x][i]];
			if( d[x]+1==d[e.to] && (f=DFS(e.to,min(a,e.cap-e.flow)))>0 )
			{
				e.flow+=f;
				edges[G[x][i]^1].flow-=f;
				flow+=f;
				a-=f;
				if(a==0)
					break;
			}
		}
		return flow;
	}

	int Maxflow(int s,int t)
	{
		this->s=s,this->t=t;
		int flow=0;
		while(BFS())
		{
			memset(cur,0,sizeof(cur));
			flow+=DFS(s,INF);
		}
		return flow;
	}	
};

伪代码

下面是dfs的过程:
[c-sharp]  view plain copy
  1. ps;  
  2. While outdegree(s)>0  
  3.     up.top;  
  4.     if u<>t  
  5.         if outdegree(u)>0  
  6.             设(u,v)为层次图中的一条边;  
  7.             pp,v;     
  8.         else  
  9.             从p和层次图中删除点u,  
  10.             以及和u连接的所有边;  
  11.     else  
  12.         增广p(删除了p中的饱和边);  
  13.         令p.top为p中从s可到达的最后顶点;  
  14. end while  

在程序里,p表示找到的增广路径,p.top为路径中的最后一个顶点。一开始,p中只有源点。

整个While循环分为2个操作。如果p的最后一个顶点为汇点,也就是说找到了增广路,那么对p增广,注意到增广后一定有一条或多条p中的边被删除了。这时,我们使增广路径后退至p中从源点可到达的最后一个顶点。

如果p的最后一个顶点不为汇点,那么观察最后那个的顶点u 。若在层次图中存在从u连出的一条边,比如(u,v),我们就将顶点v放入路径p中,继续dfs遍历;否则,点u对之后的dfs遍历就没有用了,我们将点u以及层次图中连到u的所有边删除,并且在p中后退一个点。

Dfs过程将会不断重复这2个操作,直到从源点连出的边全部被删除为止。


nocow

bool build()//建立层次图
{
	int x,y;
	memset(d,-1,sizeof(d));
	memset(G,-1,sizeof(G));
	bg=ed=d[s]=0;Q[ed++]=s;G[s]=g[s];
	while(bg<ed)
	{
		x=Q[bg++];
		for(int i=g[x];i+1;i=np[i])
		{
			y=to[i];
			if(cap[i]&&d[y]==-1)
			{
				d[y]=d[x]+1;G[y]=g[y];
				if(y==t)return true;
				Q[ed++]=y;
			}
		}
	}
	return false;
}
 
int find(int x,int low=inf)//进行增广
{
	if(x==t)return low;
	int ret=0,y;
	for(int &i=G[x];i+1;i=np[i])//注意i是引用
	{
		y=to[i];
		if(cap[i] && d[y]==d[x]+1 && (ret=find(y,low<?cap[i])))
		{
			cap[i]-=ret;cap[vp[i]]+=ret;
			return ret;
		}
	}
	return 0;
}
 
int dinic()//主过程
{
	int flow;
	while(build())
		while(flow=find(s))
			cnt+=flow;
	return 0;
}

非递归

//Author: dd_engi
void Dinic()
{
    for(;;){
        BFS();
        if(D[T]==-1)break;
        int path_n=0;
        int x=S;
        memcpy(cur,E,sizeof(cur));
        for(;;){
            if(x==T){
                int mink=-1,delta=INT_MAX;
                for(int i=0;i<path_n;++i){
                    if(path[i]->c<delta){
                        delta=path[i]->c;
                        mink=i;
                    }
                }
                for(int i=0;i<path_n;++i){
                    path[i]->c-=delta;
                    path[i]->back->c+=delta;
                }
                path_n=mink;
                x=path[path_n]->x;
            }
            edge* e;
            for(e=cur[x];e;e=e->next){
                if(e->c==0)
                    continue;
                int y=e->y;
                if(D[x]+1==D[y])
                    break;
            }
            cur[x]=e;
            if(e){
                path[path_n++]=e;
                x=e->y;
            }
            else{
                if(path_n==0)
                    break;
                D[x]=-1;
                --path_n;
                x=path[path_n]->x;
            }
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值