网络流算法之一

1. Edmonds-karp 算法

用广度优先搜索来实现对增广路径p的计算,即如果增广入径是残留网络中从(s到t的最短路径,就能改进FORD-FULKERSON的界,

称Ford-Fulkerson方法的这种实现为Edmonds-karp算法,时间复杂度为O(VE^2);

HDU 3549

View Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <deque>

using namespace std;

int cap[100][100];
int a[100];
int flow[100][100];
int path[1010];
int N,M;
const int inf = 0x7f7f7f7f;
int f;


int Scan()
{
int res = 0 , ch ;
while( !( ( ch = getchar() ) >= '0' && ch <= '9' ) )
{
if( ch == EOF ) return 1 << 30 ;
}
res = ch - '0' ;
while( ( ch = getchar() ) >= '0' && ch <= '9' )
res = res * 10 + ( ch - '0' ) ;
return res ;
}
void BFS( )
{
int i, j, k, t, u, v;
f = 0;
memset(flow, 0, sizeof(flow));
for (; ; )
{
memset(a, 0, sizeof(a));
memset(path, 0, sizeof(path));
deque<int>q;
a[1] = inf;
q.push_back(1);
while (!q.empty( ))
{
t = q.front( );
q.pop_front( );
for (i = 0; i <= N; i++)
if (!a[i] && flow[t][i] < cap[t][i] )
{
path[i] = t;
a[i] = min(a[t], cap[t][i] - flow[t][i]);
q.push_back(i);
}
}
if (a[N] == 0)
break;
for (u = N; u != 1; u = path[u])
{
flow[path[u]][u] += a[N];
flow[u][path[u]] -= a[N];

}
f += a[N];
}
printf("%d\n",f);
}

int main( )
{
int T, l = 0, i, b, c, d;
scanf("%d", &T);
while (T--)
{
l++;
scanf("%d%d", &N, &M);
memset(cap, 0, sizeof(cap));
for (i = 0; i < M; i++) {
//scanf("%d%d%d", &d, &b, &c);
d = Scan();
b = Scan();
c = Scan();
cap[d][b] += c;
}
printf("Case %d: ",l);
BFS( );
}
return 0;
}

2.压入与重标记算法

算法导论说,目前最快速的实现都是基于压入与重标记方法的。

运用该方法的算法分为好几种:

1.一般的预流推进算法

在残余网络中,维护一个预流,不断对活跃点进行push或release操作来重新调整

整个预留,直到不能操作。时间复杂度O(V*E*E)。

2.先进先出队列预留推进算法

在残余网路中,以先进先出对列维护活跃点,时间复杂度为O(V*V*V);

3.最高标号预留推进算法(HLPP)

在残余网络中,每次检查最高标号的活跃点,需要用到优先队列,

时间复杂度O(V*V*E^0.5)

View Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <deque>

using namespace std;
deque<int>q;
int cap[16][16]; //存储网络容量C,原来数组开了1000,TLE了N久
int flow[16][16]; //存储流过容量f
int e[16]; //每个顶点余流
int h[16]; //每个定点高度
int visit[16]; //标记顶点
int N,vertix;

int Scan()
{
int res = 0 , ch ;
while( !( ( ch = getchar() ) >= '0' && ch <= '9' ) )
{
if( ch == EOF ) return 1 << 30 ;
}
res = ch - '0' ;
while( ( ch = getchar() ) >= '0' && ch <= '9' )
res = res * 10 + ( ch - '0' ) ;
return res ;
}

const int inf = 0x7f7f7f7f;

int min( int x, int y)
{
return x < y ? x : y;
}

void Push( int u, int v)
{
int x = cap[u][v] - flow[u][v];
if( h[u] == h[v] + 1 && e[u] > 0 && x > 0 )
{
x = min(e[u], x);
flow[u][v] += x;
flow[v][u] = -flow[u][v];
e[u] -= x;
e[v] += x;
if( !visit[v] && v != 1 && v != vertix )
{
q.push_back( v );
visit[v] = 1;
}
}
}

void Relable(int u )
{
int H = inf;
if( e[u] > 0 && u != 1 && u != vertix )
{
for( int i = 1; i <= vertix; i++)
{
int x = cap[u][i] - flow[u][i];
if(x > 0 && h[i] < H)
{
H = h[i];
}
}
if( h[u] <= H)
{
h[u] = H + 1;
visit[u] = 1;
q.push_back( u );
}
}
}

void Initialize_Preflow( )
{
memset(h, 0, sizeof(h));
memset(e, 0, sizeof(e));
memset(flow, 0,sizeof(flow));
memset(visit,0, sizeof(visit));
h[1] = vertix;
visit[1] = 1;
q.push_back( 1 );
for( int i = 1; i <= vertix; i++)
{
if (cap[1][i])
{
flow[1][i] = cap[1][i];
flow[i][1] = -cap[1][i];
e[i] = cap[1][i];
e[1] = e[1] - cap[1][i];
visit[i] = 1;
q.push_back(i);
}
}
}

void solve(int x )
{
while( !q.empty() )
{
int u = q.front( );
visit[u] = 0;
q.pop_front( );
for( int i = 1; i <= vertix; i++)
{
Push(u, i);
}
Relable( u );
}
int ans = 0;
for( int i = 1; i <= vertix; i++)
{
ans += flow[1][i];
}
printf("Case %d: %d\n", x, ans);
}

int main( )
{
int a, b, c, l = 0, T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&vertix, &N);
l++;
q.clear();
memset(cap, 0, sizeof(cap));
for( int i = 1; i <= N; i++)
{
//scanf("%d%d%d",&a,&b, &c);
a = Scan();
b = Scan();
c = Scan();
cap[a][b] += c;
}
Initialize_Preflow( );
solve(l);
}
return 0;
}
/*
6
6
10
1 2 16
1 3 13
2 3 10
3 2 4
2 4 12
4 3 9
3 5 14
5 4 7
5 6 4
4 6 20
*/





posted on 2012-03-08 23:24  more think, more gains  阅读(558)  评论(0编辑  收藏  举报

导航