最大流ISAP算法模版
唉,说多了都是泪,贴一下ISAP的代码就让初学者参考一下,有问题请指出。
#include<iostream> #include<vector> using std::vector; #include<deque> #include<stack> using std::stack; using std::deque; #include<algorithm> using std::cin; template <typename T> class ISAP { public: ISAP() { }; template<typename U> struct Edge { Edge(int f, int t, U c, U fl) :from(f), to(t), cap(c), flow(fl) {}; Edge() {}; int from, to; U cap, flow; }; int N; //顶点的总数 int E; //边的总数 int s; //指定源s int t; //指定目的t int cE; //目前边数 vector<Edge<T>> Ed; //存放边 vector<vector<int>> G;//图中一个顶点关联的边的标号 vector<int> d;//距离标号 vector<bool> vis;//表明是否被访问过 vector<int> pre;//父亲结点 vector<int> gap;//gap优化 void Init() { cin >> N >> E; Ed.resize(E); G.resize(N + 1); d.resize(N + 1); pre.resize(N + 1); gap.resize(N + 1); for (int i = 0; i < N + 1; i++) d[i] = 0; vis.resize(N + 1); for (int i = 0; i < N + 1; i++) vis[i] = false; for (int i = 0; i < N + 1; i++) gap[i] = 0; cE = 0; s = 1; t = N; for (int i = 0; i < E; i++) { int u, v; T c; cin >> u >> v >> c; addedge(u, v, c); } } //生成初始距离标号 void make_d() { vis[t] = true; //标记终点为访问过 deque<int> dq; //队列,广度优先搜索找标记所有到终点距离 dq.push_back(t); //压入终点 d[t] = 0; //终点到终点距离为0 while (!dq.empty()) //队列为空,退出循环,所有点都被标记了 { int front = dq.front(); dq.pop_front(); //获得队首,并弹出 int Gsize = G[front].size(); //该结点邻居的数量 for (int i = 0; i < Gsize; i++) //遍历该结点有所的邻居 { int Enum = G[front][i]; //找出结点和邻居关联的边的编号 if (front == Ed[Enum].to) //如果结点是这条边的终点 { int aim = Ed[Enum].from; //获得边的起点 if (Ed[Enum].cap - Ed[Enum].flow>0 && !vis[aim])//邻居有残余流量流向结点,并且邻居没有被访问过 { d[aim] = d[front] + 1; //标记邻居的距离为结点距离+1 gap[d[aim]]++; //有d[aim]距离的结点个数+1 vis[aim] = true; //标记邻居为访问过 dq.push_back(aim); //将邻居压入队列 } } else if (front == Ed[Enum].from) //结点为边的起点 { int aim = Ed[Enum].to; //获得邻居 if (Ed[Enum].flow > 0 && !vis[aim])//邻居有残余流量流向起点,并且邻居没有被访问过 { d[aim] = d[front] + 1; //更新邻居的距离 gap[d[aim]]++; //有d[aim]距离的结点个数+1 vis[aim] = true; //标记邻居为访问过 dq.push_back(aim); //将邻居压入队列 } } } } for (int i = 0; i < N + 1; i++) vis[i] = false; } void search() { pre[s] = -1; //特殊处理,起点在增广路径中没有前置边,置为-1 bool flag = true; //是否退出循环的标志 while (flag) { //找增广路 int cur = s; //当前结点为起始结点 T minFlow = 10000000; //流无穷大 while (cur != t) //当前结点未到达终止结点 { int Gsize = G[cur].size(); //当前结点邻居的数量 bool find = false; //标记没有找到可行孤 int Minaimdis = N - 1; //在找不到可行孤的情况下,标记最小距离的孤 for (int i = 0; i < Gsize; i++) //遍历没有邻居 { Edge<T> &e = Ed[G[cur][i]]; //当前邻居关联的边 if (e.to == cur && e.flow > 0) //当前结点是终止结点,并且有残余流量流向邻居结点 { int from = e.from; //邻居结点 if (d[from] == d[cur] - 1) //如果满足邻居结点的距离 + 1 = 当前结点的距离 { find = true; //找到可行孤 pre[from] = G[cur][i]; //标记邻居结点的前置边 cur = from; //当前结点更新为邻居结点 minFlow = std::min(minFlow, e.flow); //更新增广路的流量 break; //不用再从邻居中找了 } Minaimdis = std::min(Minaimdis, d[from]); //邻居没有找到,更新最小距离的孤 } else if (e.from == cur && e.cap - e.flow > 0) //同上 { int to = e.to; if (d[to] == d[cur] - 1) { find = true; pre[to] = G[cur][i]; cur = to; minFlow = std::min(minFlow, e.cap - e.flow); break; } Minaimdis = std::min(Minaimdis, d[to]); } } if (!find) //未找到可行孤 { gap[d[cur]]--; //将当前结点距离数量-1 if (gap[d[cur]] == 0) { flag = false; break; } //如果该距离数量变为0,则出现断层,已经找到找大流 d[cur] = Minaimdis + 1; //更新最小距离,最在为N gap[d[cur]]++; //更新gap int edgenum = pre[cur]; //找到当前结点关联的前置边 if (edgenum == -1)cur = s; //表示没有前置边,为起点,标记当前结点为起点 else if (cur == Ed[edgenum].to) //如果当前结点为前置边的终点 cur = Ed[edgenum].from; //标记当前结点为前置边的起点 else cur = Ed[edgenum].to; } } if (cur == t)//找到增广路,调整流量 { while (cur != s) { Edge<T>& e = Ed[pre[cur]]; if (cur == e.to) { e.flow += minFlow; cur = e.from; } else { e.flow -= minFlow; cur = e.to; } } } } } void output() { T ans = 0; for (int i = 0; i < G[s].size(); i++) { ans += Ed[G[s][i]].flow; } using std::cout; cout << ans; } void addedge(int from, int to, T cap) { G[from].push_back(cE); G[to].push_back(cE); Ed[cE++] = Edge<T>(from, to, cap, 0); } }; int main() { ISAP<int> isap; isap.Init(); isap.make_d(); isap.search(); isap.output(); return 0; }