Edmond Karp 算法:
#include <iostream> #include <queue> #include<string.h> using namespace std; #define arraysize 201 int maxData = 0x7fffffff; int capacity[arraysize][arraysize]; //记录残留网络的容量 int flow[arraysize]; //标记从源点到当前节点实际还剩多少流量可用 int pre[arraysize]; //标记在这条路径上当前节点的前驱,同时标记该节点是否在队列中 int n,m; queue<int> myqueue; int BFS(int src,int des) { int i,j; while(!myqueue.empty()) //队列清空 myqueue.pop(); for(i=1;i<m+1;++i) { pre[i]=-1; } pre[src]=0; flow[src]= maxData; myqueue.push(src); while(!myqueue.empty()) { int index = myqueue.front(); myqueue.pop(); if(index == des) //找到了增广路径 break; for(i=1;i<m+1;++i) { if(i!=src && capacity[index][i]>0 && pre[i]==-1) { pre[i] = index; //记录前驱 flow[i] = min(capacity[index][i],flow[index]); //关键:迭代的找到增量 myqueue.push(i); } } } if(pre[des]==-1) //残留图中不再存在增广路径 return -1; else return flow[des]; } int EK(int src,int des) { int increasement= 0; int sumflow = 0; while((increasement=BFS(src,des))!=-1) { int k = des; //利用前驱寻找路径 while(k!=src) { int last = pre[k]; capacity[last][k] -= increasement; //改变正向边的容量 capacity[k][last] += increasement; //改变反向边的容量 k = last; } sumflow += increasement; } return sumflow; } int main() { int i,j; int start,end,ci; while(cin>>n>>m) { memset(capacity,0,sizeof(capacity)); memset(flow,0,sizeof(flow)); for(i=0;i<n;++i) { cin>>start>>end>>ci; if(start == end) //考虑起点终点相同的情况 continue; capacity[start][end] +=ci; //此处注意可能出现多条同一起点终点的情况(重边) } cout<<EK(1,m)<<endl; } return 0; }
Dinic非递归版:
#define N 5000 #define M 1505 #define inf 536870912 //N为点数 M为边数 struct Edge{ int from, to, cap, nex; }edge[M*10];//注意这个一定要够大 不然会re 还有反向弧 int head[N], edgenum; void addedge(int u, int v, int cap){ Edge E = { u, v, cap, head[u]}; edge[ edgenum ] = E; head[u] = edgenum ++; Edge E2= { v, u, 0, head[v]}; edge[ edgenum ] = E2; head[v] = edgenum ++; } int sign[N], s, t; bool BFS(int from, int to){ memset(sign, -1, sizeof(sign)); sign[from] = 0; queue<int>q; q.push(from); while( !q.empty() ){ int u = q.front(); q.pop(); for(int i = head[u]; i!=-1; i = edge[i].nex) { int v = edge[i].to; if(sign[v]==-1 && edge[i].cap) { sign[v] = sign[u] + 1, q.push(v); if(sign[to] != -1)return true; } } } return false; } int Stack[M*4], top, cur[M*4]; int dinic(){ int ans = 0; while( BFS(s, t) ) { memcpy(cur, head, sizeof(head)); int u = s; top = 0; while(1) { if(u == t) { int flow = inf, loc;//loc 表示 Stack 中 cap 最小的边 for(int i = 0; i < top; i++) if(flow > edge[ Stack[i] ].cap) { flow = edge[Stack[i]].cap; loc = i; } for(int i = 0; i < top; i++) { edge[ Stack[i] ].cap -= flow; edge[Stack[i]^1].cap += flow; } ans += flow; top = loc; u = edge[Stack[top]].from; } for(int i = cur[u]; i!=-1; cur[u] = i = edge[i].nex)//cur[u] 表示u所在能增广的边的下标 if(edge[i].cap && (sign[u] + 1 == sign[ edge[i].to ]))break; if(cur[u] != -1) { Stack[top++] = cur[u]; u = edge[ cur[u] ].to; } else { if( top == 0 )break; sign[u] = -1; u = edge[ Stack[--top] ].from; } } } return ans; }
Dinic 递归版:
#define inf 1000000 #define N 1000 #define M 100000 //N为点数 M为边数 inline int Min(int a,int b){return a>b?b:a;} //注意这个类型是int struct Edge{ int from, to, cap, nex; }edge[M*2];//双向边,注意RE 注意这个模版是 相同起末点的边 同时有效而不是去重 int head[N],edgenum;//2个要初始化-1和0 void addedge(int u, int v, int cap){//网络流要加反向弧,即u->v 为10 则 v->u为 -10 Edge E = {u, v, cap, head[u]}; edge[ edgenum ] = E; head[ u ] = edgenum++; Edge E2 = {v, u, 0, head[v]}; //这里的cap若是单向边要为0 edge[ edgenum ] = E2; head[ v ] = edgenum++; } int dis[N], cur[N];//dis[i]表示i点距离起点的距离 cur[i]表示i点所连接的边中 正在考虑的边 优化不再考虑已经用过的点 初始化为head bool vis[N]; bool BFS(int Start,int End){//跑一遍最短路 memset(vis,0,sizeof(vis)); memset(dis,-1,sizeof(dis)); queue<int>Q; Q.push(Start); dis[Start]=0; vis[Start]=1; while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i = head[u]; i != -1; i = edge[i].nex){ Edge E = edge[i]; if( !vis[E.to] && E.cap > 0) { vis[ E.to ] = true; dis[ E.to ] = dis[ u ] + 1; if(E.to == End) return true; Q.push( E.to ); } } } return false; } int DFS(int x, int a,int End){//当前 流入x 的流量是a 流量a 是所有流过边中 边权的最小值 if( x == End || a == 0)return a; int flow = 0, f; //flow表示从x点流到下面所有点,最大的流量 for(int& i = cur[x]; i != -1; i = edge[i].nex) { Edge& E = edge[i]; if(dis[x] + 1 == dis[E.to] && (f = DFS(E.to , Min(a, E.cap), End))>0 ) { E.cap -= f; edge[ i^1 ].cap += f;//反向边要减掉 flow += f; a -= f; if(a==0)break; } } return flow; } int Maxflow(int Start,int End){ int flow=0; while(BFS(Start,End)){ //当存在源点到汇点的路径时 memcpy(cur,head,sizeof(head));//把head的数组复制过去 flow += DFS(Start, inf, End); } return flow; }
ISAP 版:
typedef struct { int v, next, val; } edge; const int MAXN = 20010; const int MAXM = 500010; edge e[MAXM]; int p[MAXN], eid; inline void init() { memset(p, -1, sizeof(p)); eid = 0; } //有向 inline void insert1(int from, int to, int val) { e[eid].v = to; e[eid].val = val; e[eid].next = p[from]; p[from] = eid++; swap(from, to); e[eid].v = to; e[eid].val = 0; e[eid].next = p[from]; p[from] = eid++; } //无向 inline void insert2(int from, int to, int val) { e[eid].v = to; e[eid].val = val; e[eid].next = p[from]; p[from] = eid++; swap(from, to); e[eid].v = to; e[eid].val = val; e[eid].next = p[from]; p[from] = eid++; } int n, m; //n为点数 m为边数 int h[MAXN]; int gap[MAXN]; int source, sink; inline int dfs(int pos, int cost) { if (pos == sink) { return cost; } int j, minh = n - 1, lv = cost, d; for (j = p[pos]; j != -1; j = e[j].next) { int v = e[j].v, val = e[j].val; if(val > 0) { if (h[v] + 1 == h[pos]) { if (lv < e[j].val) { d = lv; } else { d = e[j].val; } d = dfs(v, d); e[j].val -= d; e[j ^ 1].val += d; lv -= d; if (h[source] >= n) { return cost - lv; } if (lv == 0) { break; } } if (h[v] < minh) { minh = h[v]; } } } if (lv == cost) { --gap[h[pos]]; if (gap[h[pos]] == 0) { h[source] = n; } h[pos] = minh + 1; ++gap[h[pos]]; } return cost - lv; } int sap(int st, int ed) { source = st; sink = ed; int ret = 0; memset(gap, 0, sizeof(gap)); memset(h, 0, sizeof(h)); //gap[st] = n; gap[0] = n; while (h[st] < n) { ret += dfs(st, INT_MAX); } return ret; }