sap算法用于求网络流的最大流
算法框架:
1.给每个点标高度 只有高处的水才能往地处流 一开始的高度都为0
2.在所有的可行弧中不断的寻找增广路 可行弧的定义为 {(i,j) | h[i]=h[j]+1}
3.遍历完当前节点后(流不出去了) 重新标记当前点的高度(保证下次再来的时候有路可走) h[i]=min(h[j])+1;
4.检查是否存在断层 如果出现断层 则图中已不存在增广路 算法可以结束 否则从源点开始继续遍历
下面的代码的题目是 usaco 4.2.1 草地排水
/*
PROG:ditch
LANG:C++
*/
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
#define bug cout<<"bug"<<endl;
const int maxn = 300;
const int inf = 123456789;
int s, t;
int g[maxn][maxn];
int h[maxn], vh[maxn];//h个点的高度 vh各个高度点的数量
int n, m;
int aug(int k, int fn)
{
if (k == t) return fn;//到大汇点 返回
int left = fn, delta = 0;
int minh = n - 1;//注意这里 是n-1
for (int i = 1; i <= n; i++)
if (g[k][i] > 0)
{
if (h[k] == h[i] + 1)
{
delta = aug(i, min(left, g[k][i]));
g[k][i] -= delta;
g[i][k] += delta;
left -= delta;
if (left == 0 || h[s] == n) return fn - left;//这两个一定要加
}
minh = min(minh, h[i]);
}
if (left == fn)//出不去就升高自己的高度
{
vh[h[k]]--;
if (vh[h[k]] == 0) h[s] = n;//出现断层了 gap优化
h[k] = minh + 1;
vh[h[k]]++;
}
return fn - left;
}
int sap()
{
int ans = 0;
vh[0] = n;
while (h[s] < n)
ans += aug(s, inf);
return ans;
}
int main()
{
freopen("ditch.in", "r", stdin);
freopen("ditch.out", "w", stdout);
cin >> m >> n;
int a, b, c;
for (int i = 1; i <= m; i++)
{
cin >> a >> b >> c;
g[a][b] += c;
}
s = 1, t = n;
cout << sap() << endl;
fclose(stdin);
fclose(stdout);
return 0;
}
这里是用邻接表写的
/*
PROG:ditch
LANG:C++
*/
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
struct node
{
int d, w;
node *next, *op;//op为反向边的地址
};
const int maxn = 300;
const int inf = 123456789;
node *adj[maxn];
int h[maxn], vh[maxn];
int n, m;//n个点 m条边
int s, t;//源点和汇点
void edge(int a, int b, int c)
{
node *p = new node, *q = new node;
//正向边 和 反向边
p->d = b;
p->w = c;
p->next = adj[a];
adj[a] = p;
q->d = a;
q->w = 0;//这里要注意 反向边流量为0
q->next = adj[b];
adj[b] = q;
p->op = q;
q->op = p;
}
int aug(int k, int fm)
{
if(k == t)
return fm;
int left = fm, delta = 0;
int minh = n-1;
for(node *p = adj[k]; p != NULL; p = p->next)
if(p->w > 0)
{
if(h[k] == h[p->d] + 1)
{
delta = aug(p->d, min(left, p->w));
p->w -= delta;
p->op->w += delta;
left -= delta;
if(left == 0 || h[s] == n)
return fm - left;
}
minh = min(minh, h[p->d]);
}
if(fm == left)
{
vh[h[k]]--;
if(vh[h[k]] == 0)
h[s] = n;
h[k] = minh + 1;
vh[h[k]]++;
}
return fm - left;
}
int sap()
{
int ans = 0;
memset(h, 0, sizeof(h));
memset(vh, 0, sizeof(vh));
vh[0] = n;
while(h[s] < n)
ans += aug(s, inf);
return ans;
}
int main()
{
freopen("ditch.in", "r", stdin);
freopen("ditch.out", "w", stdout);
cin >> m >> n;
int a, b, c;
for(int i = 1; i <= m; i++)
{
cin >> a >> b >> c;
edge(a, b, c);
}
s = 1, t = n;
cout << sap() << endl;
fclose(stdin);
fclose(stdout);
return 0;
}