最大流EK、Dinic、SAP三种算法模板

EK

//Max_flow
//@2018/05/02 Wednesday
//EK algorithm [Edmonds Karp] O(V*E^2) O(v^2)
//by Tawn
#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e3;
const int INF = 0x3f3f3f3f;

int n,m; //n - Vertices  m - edges
int pre[maxn]; //record predecesor and sign if it is visited
int cap[maxn][maxn]; //record the capacity of residual network
int flow[maxn]; //record the residual flow from starting vertex to current vertex 
queue <int> q;

int bfs(int st, int ed)
{
  memset(pre,-1,sizeof(pre));
  while(!q.empty()) q.pop();
  pre[st] = 0;
  flow[st] = INF;
  q.push(st);
  while(!q.empty())
  {
  	int t = q.front();
  	q.pop();
  	if(t == ed) break;
  	for(int i = 1; i <= n; i++)
  	{
  		if(pre[i] == -1 && cap[t][i] > 0)
  		{
  			pre[i] = t;
  			flow[i] = min(flow[t],cap[t][i]);
  			q.push(i);
  		}
  	}
  }
  if(pre[ed] == -1)  return -1;
  else              return flow[ed];
}


int EK(int st, int ed)
{
	int res = 0; //the augmenting flow
	int sum = 0; //the max_flow
	while((res = bfs(st,ed)) != -1)//argumenting path
	{
		int k = ed;
		while(k != st)
		{
			int f = pre[k];
			cap[f][k] -= res;
			cap[k][f] += res;//reversible edge
			k = f;
		}
		sum += res;
	}
	return sum;
}


int main()
{
   int s,t,c;
   scanf("%d%d",&n,&m);
   memset(cap,0,sizeof(cap));
   for(int i = 0; i < m; i++)
   {
   	scanf("%d%d%d",&s,&t,&c);
   	cap[s][t] = c;
   }
   int ans = EK(1,n);
   printf("%d\n",ans);
   return 0;
}

Dinic

当前弧优化,维护一个cur数组,放入所有的h[i]];每次dfs的时候用int &i = cur[x];

//Max_flow
//@2018/05/04 Friday
//Dinic  O(n^2 * m)  O(m*3*2)
//by Tawn 
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>

using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 200 + 10;
const int maxm = 200 + 10;

int n,m;
int l[maxn];//记录层数
int h[maxn];//链式前向星
int cur[maxn];
int tot = 0;

struct edge
{
  int to;
  int c;
  int next;
  edge(int x = 0, int y = 0, int z = 0) : to(x), c(y), next(z) {}
 }es[maxm*2];//记录边 注意是2倍

void add_edge(int u, int v, int c)
{
    es[tot] = edge(v,c,h[u]);
    h[u] = tot++;
}

bool bfs(int s, int t)
{
   memset(l,0,sizeof(l));
   l[s] = 1;
   queue <int> q;
   q.push(s);
   while(!q.empty())
   {
    int u = q.front();
    q.pop();
    if(u == t)  return true;
    for(int i = h[u]; i != -1; i = es[i].next)
        {
         int v = es[i].to;
         if(!l[v] && es[i].c) {l[v] = l[u] + 1; q.push(v);}
        }
   }
   return false;
}

int dfs(int x, int t, int mf)
{
    if(x == t) return mf;
    int ret = 0;
    for(int i = cur[x]; i != -1; i = es[i].next)
    {
      if(es[i].c && l[x] == l[es[i].to] - 1)
      {
        int f = dfs(es[i].to,t,min(es[i].c,mf - ret));
        es[i].c -= f;
        es[i^1].c += f;
        ret += f;
        if(ret == mf) return ret;
      }
    }
    return ret;
}

int dinic(int s, int t)
{
  int ans = 0;
  while(bfs(s,t)) 
  {
   for(int i = 0; i <= n; i++) cur[i] = h[i];
   ans += dfs(s,t,INF);
   }
  return ans;
}

int main()
{
   while(~scanf("%d%d",&n,&m))
   {
   tot = 0;
   memset(h,-1,sizeof(h));
   int u,v,c;
   for(int i = 0; i < m; i++)
   {
    scanf("%d%d%d",&u,&v,&c);
    add_edge(u,v,c);
    add_edge(v,u,0);//增加反向边
   }
   int ans = dinic(1,n); 
   printf("%d\n",ans);
   }
   return 0;   
}

SAP

	//Max_flow
	//@2018/05/04 Friday
	//SAP  O(n^2 * m)  O(m*3*2)
	//by Tawn 
	#include <iostream>
	#include <cstdio>
	#include <algorithm>
	#include <queue>
	#include <cstring>

	using namespace std;
	const int INF = 0x3f3f3f3f;
	const int maxn = 200 + 10;
	const int maxm = 200 + 10;

	int n,m;
	int head[maxn];//链式前向星
	int tot = 0;

	struct edge
	{
	  int to;
	  int c;
	  int next;
	  edge(int x = 0, int y = 0, int z = 0) : to(x), c(y), next(z) {}
	 }es[maxm*2];//记录边 注意是2倍

	void add_edge(int u, int v, int c)
	{
	    es[tot] = edge(v,c,head[u]);
	    head[u] = tot++;
	}


	int SAP(int s, int t)
	{
		int numh[maxn],h[maxn],ce[maxn],pre[maxn];
		//numh 记录gap优化的统计高度数量数组,h 距离标号数组,ce 当前弧,pre前驱数组
		int f, ans = 0, u, temp, neck, i; //初始化最大流为0
		memset(h,0,sizeof(h));
		memset(numh,0,sizeof(numh));
		memset(pre,-1,sizeof(pre));
		for(i = 1; i <= n; i++)  ce[i] = head[i];
		numh[0] = n;
	    u = s;
	    while(h[s] < n)
	    {
	    	//寻找增广路
	    	if(u == t)
	    	{
	    		f = INF;
	    		for(i = s; i != t; i = es[ce[i]].to)
	    		{
	    			if(f > es[ce[i]].c)
	    			{
	    				neck = i;
	    				f = es[ce[i]].c;
	    			}
	    		}
	    		for(i = s; i != t; i = es[ce[i]].to)
	    		{
	    			temp = ce[i];
	    			es[temp].c -= f;
	    			es[temp^1].c += f;
	    		}
	    		ans += f;
	    		u = neck;
	    	}

	    	//寻找可行弧
	    	for(i = ce[u]; i != -1; i = es[i].next)
	    		if(es[i].c && h[u] == h[es[i].to] + 1)  break;

	       //寻找增广路
	    	if(i != -1)
	    	{
	    		ce[u] = i;
	    		pre[es[i].to] = u;
	    		u = es[i].to;
	    	}
	    	else
	    	{
	    		if(!--numh[h[u]]) break; //gap optimization
	    		ce[u] = head[u];
	    		for(temp = n, i = head[u]; i != -1; i = es[i].next)
	    			if(es[i].c)  temp = min(temp, h[es[i].to]);

	    		h[u] = temp + 1;
	    		++numh[h[u]];
	    		if(u != s) u = pre[u];//重标号并且从当前点前驱重新增广 
	    	}

	    }
	    return ans;
	}

	int main()
	{
	   while(~scanf("%d%d",&n,&m))
	   {
	   tot = 0;
	   memset(head,-1,sizeof(head));
	   int u,v,c;
	   for(int i = 0; i < m; i++)
	   {
	    scanf("%d%d%d",&u,&v,&c);
	    add_edge(u,v,c);
	    add_edge(v,u,0);//增加反向边
	   }
	   int ans = SAP(1,n); 
	   printf("%d\n",ans);
	   }
	   return 0;   
	}

/* * (有向)图的深度优先遍历算法模板 */ package dsa; public abstract class DFS extends GraphTraverse { //变量 protected static int clock = 0;//遍历过程中使用的计时钟 //构造方法 public DFS(Graph g) { super(g); } //深度优先遍历算法 protected Object traverse(Vertex v, Object info) {//从顶点v出发,做深度优先查找 if (UNDISCOVERED != v.getStatus()) return null;//跳过已访问过的顶点(针对非连通图) v.setDStamp(clock++); v.setStatus(DISCOVERED); visit(v, info);//访问当前顶点 for (Iterator it = v.outEdges(); it.hasNext();) {//检查与顶点v Edge e = (Edge)it.getNext();//通过边e = (v, u) Vertex u = (Vertex)e.getVPosInV(1).getElem();//相联的每一顶点u switch (u.getStatus()) {//根据u当前的不同状态,分别做相应处理 case UNDISCOVERED ://若u尚未被发现,则 e.setType(TREE);//e被归类为“树边” traverse(u, info);//从u出发,继续做深度优先查找 break; case DISCOVERED ://若u已经被发现,但对其访问尚未结束,则 e.setType(BACKWARD);//将e归类为“后向跨边” break; default ://VISITED,即对u的访问已经结束 if (u.getDStamp() < v.getDStamp())//若相对于v,u被发现得更早,则 e.setType(CROSS);//将e归类为“横跨边” else//否则 e.setType(FORWARD);//将e归类为“前向跨边” break; } }//至此,v的所有邻居都已访问结束,故 v.setFStamp(clock++); v.setStatus(VISITED);//将v标记为VISITED return null;//然后回溯 } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值