网络流之最大流sap算法

来源:互联网 发布:文明5mac版汉化 编辑:程序博客网 时间:2024/05/17 08:41

sap算法用于求网络流的最大流

算法框架:

1.给每个点标高度 只有高处的水才能往地处流 一开始的高度都为0

2.在所有的可行弧中不断的寻找增广路 可行弧的定义为 {(i,j) | h[i]=h[j]+1}

3.遍历完当前节点后(流不出去了) 重新标记当前点的高度(保证下次再来的时候有路可走) h[i]=min(h[j])+1;

4.检查是否存在断层 如果出现断层 则图中已不存在增广路 算法可以结束 否则从源点开始继续遍历


下面的代码的题目是 usaco 4.2.1 草地排水

/*PROG:ditchLANG: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:ditchLANG: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;}


原创粉丝点击