src/glpnet07.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
alpar@1
     1
/* glpnet07.c (Ford-Fulkerson algorithm) */
alpar@1
     2
alpar@1
     3
/***********************************************************************
alpar@1
     4
*  This code is part of GLPK (GNU Linear Programming Kit).
alpar@1
     5
*
alpar@1
     6
*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
alpar@1
     7
*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
alpar@1
     8
*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
alpar@1
     9
*  E-mail: <mao@gnu.org>.
alpar@1
    10
*
alpar@1
    11
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    12
*  under the terms of the GNU General Public License as published by
alpar@1
    13
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    14
*  (at your option) any later version.
alpar@1
    15
*
alpar@1
    16
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    17
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    18
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    19
*  License for more details.
alpar@1
    20
*
alpar@1
    21
*  You should have received a copy of the GNU General Public License
alpar@1
    22
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    23
***********************************************************************/
alpar@1
    24
alpar@1
    25
#include "glpenv.h"
alpar@1
    26
#include "glpnet.h"
alpar@1
    27
alpar@1
    28
/***********************************************************************
alpar@1
    29
*  NAME
alpar@1
    30
*
alpar@1
    31
*  ffalg - Ford-Fulkerson algorithm
alpar@1
    32
*
alpar@1
    33
*  SYNOPSIS
alpar@1
    34
*
alpar@1
    35
*  #include "glpnet.h"
alpar@1
    36
*  void ffalg(int nv, int na, const int tail[], const int head[],
alpar@1
    37
*     int s, int t, const int cap[], int x[], char cut[]);
alpar@1
    38
*
alpar@1
    39
*  DESCRIPTION
alpar@1
    40
*
alpar@1
    41
*  The routine ffalg implements the Ford-Fulkerson algorithm to find a
alpar@1
    42
*  maximal flow in the specified flow network.
alpar@1
    43
*
alpar@1
    44
*  INPUT PARAMETERS
alpar@1
    45
*
alpar@1
    46
*  nv is the number of nodes, nv >= 2.
alpar@1
    47
*
alpar@1
    48
*  na is the number of arcs, na >= 0.
alpar@1
    49
*
alpar@1
    50
*  tail[a], a = 1,...,na, is the index of tail node of arc a.
alpar@1
    51
*
alpar@1
    52
*  head[a], a = 1,...,na, is the index of head node of arc a.
alpar@1
    53
*
alpar@1
    54
*  s is the source node index, 1 <= s <= nv.
alpar@1
    55
*
alpar@1
    56
*  t is the sink node index, 1 <= t <= nv, t != s.
alpar@1
    57
*
alpar@1
    58
*  cap[a], a = 1,...,na, is the capacity of arc a, cap[a] >= 0.
alpar@1
    59
*
alpar@1
    60
*  NOTE: Multiple arcs are allowed, but self-loops are not allowed.
alpar@1
    61
*
alpar@1
    62
*  OUTPUT PARAMETERS
alpar@1
    63
*
alpar@1
    64
*  x[a], a = 1,...,na, is optimal value of the flow through arc a.
alpar@1
    65
*
alpar@1
    66
*  cut[i], i = 1,...,nv, is 1 if node i is labelled, and 0 otherwise.
alpar@1
    67
*  The set of arcs, whose one endpoint is labelled and other is not,
alpar@1
    68
*  defines the minimal cut corresponding to the maximal flow found.
alpar@1
    69
*  If the parameter cut is NULL, the cut information are not stored.
alpar@1
    70
*
alpar@1
    71
*  REFERENCES
alpar@1
    72
*
alpar@1
    73
*  L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND
alpar@1
    74
*  Corp., Report R-375-PR (August 1962), Chap. I "Static Maximal Flow,"
alpar@1
    75
*  pp.30-33. */
alpar@1
    76
alpar@1
    77
void ffalg(int nv, int na, const int tail[], const int head[],
alpar@1
    78
      int s, int t, const int cap[], int x[], char cut[])
alpar@1
    79
{     int a, delta, i, j, k, pos1, pos2, temp,
alpar@1
    80
         *ptr, *arc, *link, *list;
alpar@1
    81
      /* sanity checks */
alpar@1
    82
      xassert(nv >= 2);
alpar@1
    83
      xassert(na >= 0);
alpar@1
    84
      xassert(1 <= s && s <= nv);
alpar@1
    85
      xassert(1 <= t && t <= nv);
alpar@1
    86
      xassert(s != t);
alpar@1
    87
      for (a = 1; a <= na; a++)
alpar@1
    88
      {  i = tail[a], j = head[a];
alpar@1
    89
         xassert(1 <= i && i <= nv);
alpar@1
    90
         xassert(1 <= j && j <= nv);
alpar@1
    91
         xassert(i != j);
alpar@1
    92
         xassert(cap[a] >= 0);
alpar@1
    93
      }
alpar@1
    94
      /* allocate working arrays */
alpar@1
    95
      ptr = xcalloc(1+nv+1, sizeof(int));
alpar@1
    96
      arc = xcalloc(1+na+na, sizeof(int));
alpar@1
    97
      link = xcalloc(1+nv, sizeof(int));
alpar@1
    98
      list = xcalloc(1+nv, sizeof(int));
alpar@1
    99
      /* ptr[i] := (degree of node i) */
alpar@1
   100
      for (i = 1; i <= nv; i++)
alpar@1
   101
         ptr[i] = 0;
alpar@1
   102
      for (a = 1; a <= na; a++)
alpar@1
   103
      {  ptr[tail[a]]++;
alpar@1
   104
         ptr[head[a]]++;
alpar@1
   105
      }
alpar@1
   106
      /* initialize arc pointers */
alpar@1
   107
      ptr[1]++;
alpar@1
   108
      for (i = 1; i < nv; i++)
alpar@1
   109
         ptr[i+1] += ptr[i];
alpar@1
   110
      ptr[nv+1] = ptr[nv];
alpar@1
   111
      /* build arc lists */
alpar@1
   112
      for (a = 1; a <= na; a++)
alpar@1
   113
      {  arc[--ptr[tail[a]]] = a;
alpar@1
   114
         arc[--ptr[head[a]]] = a;
alpar@1
   115
      }
alpar@1
   116
      xassert(ptr[1] == 1);
alpar@1
   117
      xassert(ptr[nv+1] == na+na+1);
alpar@1
   118
      /* now the indices of arcs incident to node i are stored in
alpar@1
   119
         locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */
alpar@1
   120
      /* initialize arc flows */
alpar@1
   121
      for (a = 1; a <= na; a++)
alpar@1
   122
         x[a] = 0;
alpar@1
   123
loop: /* main loop starts here */
alpar@1
   124
      /* build augmenting tree rooted at s */
alpar@1
   125
      /* link[i] = 0 means that node i is not labelled yet;
alpar@1
   126
         link[i] = a means that arc a immediately precedes node i */
alpar@1
   127
      /* initially node s is labelled as the root */
alpar@1
   128
      for (i = 1; i <= nv; i++)
alpar@1
   129
         link[i] = 0;
alpar@1
   130
      link[s] = -1, list[1] = s, pos1 = pos2 = 1;
alpar@1
   131
      /* breadth first search */
alpar@1
   132
      while (pos1 <= pos2)
alpar@1
   133
      {  /* dequeue node i */
alpar@1
   134
         i = list[pos1++];
alpar@1
   135
         /* consider all arcs incident to node i */
alpar@1
   136
         for (k = ptr[i]; k < ptr[i+1]; k++)
alpar@1
   137
         {  a = arc[k];
alpar@1
   138
            if (tail[a] == i)
alpar@1
   139
            {  /* a = i->j is a forward arc from s to t */
alpar@1
   140
               j = head[a];
alpar@1
   141
               /* if node j has been labelled, skip the arc */
alpar@1
   142
               if (link[j] != 0) continue;
alpar@1
   143
               /* if the arc does not allow increasing the flow through
alpar@1
   144
                  it, skip the arc */
alpar@1
   145
               if (x[a] == cap[a]) continue;
alpar@1
   146
            }
alpar@1
   147
            else if (head[a] == i)
alpar@1
   148
            {  /* a = i<-j is a backward arc from s to t */
alpar@1
   149
               j = tail[a];
alpar@1
   150
               /* if node j has been labelled, skip the arc */
alpar@1
   151
               if (link[j] != 0) continue;
alpar@1
   152
               /* if the arc does not allow decreasing the flow through
alpar@1
   153
                  it, skip the arc */
alpar@1
   154
               if (x[a] == 0) continue;
alpar@1
   155
            }
alpar@1
   156
            else
alpar@1
   157
               xassert(a != a);
alpar@1
   158
            /* label node j and enqueue it */
alpar@1
   159
            link[j] = a, list[++pos2] = j;
alpar@1
   160
            /* check for breakthrough */
alpar@1
   161
            if (j == t) goto brkt;
alpar@1
   162
         }
alpar@1
   163
      }
alpar@1
   164
      /* NONBREAKTHROUGH */
alpar@1
   165
      /* no augmenting path exists; current flow is maximal */
alpar@1
   166
      /* store minimal cut information, if necessary */
alpar@1
   167
      if (cut != NULL)
alpar@1
   168
      {  for (i = 1; i <= nv; i++)
alpar@1
   169
            cut[i] = (char)(link[i] != 0);
alpar@1
   170
      }
alpar@1
   171
      goto done;
alpar@1
   172
brkt: /* BREAKTHROUGH */
alpar@1
   173
      /* walk through arcs of the augmenting path (s, ..., t) found in
alpar@1
   174
         the reverse order and determine maximal change of the flow */
alpar@1
   175
      delta = 0;
alpar@1
   176
      for (j = t; j != s; j = i)
alpar@1
   177
      {  /* arc a immediately precedes node j in the path */
alpar@1
   178
         a = link[j];
alpar@1
   179
         if (head[a] == j)
alpar@1
   180
         {  /* a = i->j is a forward arc of the cycle */
alpar@1
   181
            i = tail[a];
alpar@1
   182
            /* x[a] may be increased until its upper bound */
alpar@1
   183
            temp = cap[a] - x[a];
alpar@1
   184
         }
alpar@1
   185
         else if (tail[a] == j)
alpar@1
   186
         {  /* a = i<-j is a backward arc of the cycle */
alpar@1
   187
            i = head[a];
alpar@1
   188
            /* x[a] may be decreased until its lower bound */
alpar@1
   189
            temp = x[a];
alpar@1
   190
         }
alpar@1
   191
         else
alpar@1
   192
            xassert(a != a);
alpar@1
   193
         if (delta == 0 || delta > temp) delta = temp;
alpar@1
   194
      }
alpar@1
   195
      xassert(delta > 0);
alpar@1
   196
      /* increase the flow along the path */
alpar@1
   197
      for (j = t; j != s; j = i)
alpar@1
   198
      {  /* arc a immediately precedes node j in the path */
alpar@1
   199
         a = link[j];
alpar@1
   200
         if (head[a] == j)
alpar@1
   201
         {  /* a = i->j is a forward arc of the cycle */
alpar@1
   202
            i = tail[a];
alpar@1
   203
            x[a] += delta;
alpar@1
   204
         }
alpar@1
   205
         else if (tail[a] == j)
alpar@1
   206
         {  /* a = i<-j is a backward arc of the cycle */
alpar@1
   207
            i = head[a];
alpar@1
   208
            x[a] -= delta;
alpar@1
   209
         }
alpar@1
   210
         else
alpar@1
   211
            xassert(a != a);
alpar@1
   212
      }
alpar@1
   213
      goto loop;
alpar@1
   214
done: /* free working arrays */
alpar@1
   215
      xfree(ptr);
alpar@1
   216
      xfree(arc);
alpar@1
   217
      xfree(link);
alpar@1
   218
      xfree(list);
alpar@1
   219
      return;
alpar@1
   220
}
alpar@1
   221
alpar@1
   222
/* eof */