1459(2)

/*
邻接矩阵实现ISAP

间隙优化,current
*/

// include file
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <ctime>

#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <bitset>

#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <list>
#include <functional>

using namespace std;

// typedef
typedef long long LL;
typedef unsigned long long ULL;
typedef __int64 Bint;

// 
#define read freopen("in.txt","r",stdin)
#define write freopen("out.txt","w",stdout)
#define FORi(a,b,c) for(int i=(a);i<(b);i+=c)
#define FORj(a,b,c) for(int j=(a);j<(b);j+=c)
#define FORk(a,b,c) for(int k=(a);k<(b);k+=c)
#define FORp(a,b,c) for(int p=(a);p<(b);p+=c)
#define FORii(a,b,c) for(int ii=(a);ii<(b);ii+=c)
#define FORjj(a,b,c) for(int jj=(a);jj<(b);jj+=c)
#define FORkk(a,b,c) for(int kk=(a);kk<(b);kk+=c)

#define FF(i,a)    for(int i=0;i<(a);i++)
#define FFD(i,a)   for(int i=(a)-1;i>=0;i--)

#define Z(a) (a<<1)
#define Y(a) (a>>1)

const double eps = 1e-6;
const double INFf = 1e10;
const int INFi = 1000000000;
const double Pi = acos(-1.0);

template<class T> inline T sqr(T a){return a*a;}
template<class T> inline T TMAX(T x,T y)
{
	if(x>y) return x;
	return y;
}
template<class T> inline T TMIN(T x,T y)
{
	if(x<y) return x;
	return y;
}
template<class T> inline void SWAP(T &x,T &y)
{
	T t = x;
	x = y;
	y = t;
}
template<class T> inline T MMAX(T x,T y,T z)
{
	return TMAX(TMAX(x,y),z);
}


// code begin

#define MAXN 110
int N,NP,NC,M;
int source,sink;

// graph and flow
int G[MAXN][MAXN],F[MAXN][MAXN];

// predecessor list
int pi[MAXN]; 
int CurrentNode[MAXN];

int que[MAXN]; //BFS用

int d[MAXN];     // 到汇点的距离
int numbs[MAXN]; // 每层顶点个数

void rev_BFS()
{
	int head(0),tail(0);
	memset(numbs,0,sizeof(numbs));
	// initially, all d[i] = n;
	FORi(1,N+1,1)
	{
		d[i] = N;
		numbs[d[i]]++; // numbs记录每层顶点个数
	}
	
	// start from the sink
	numbs[N]--;
	d[sink] = 0;
	numbs[ d[sink] ]++;

	que[++tail] = sink;
	while(head!=tail)
	{
		int cur = que[++head];

		// check all adjcent nodes
		FORj(1,N+1,1)
		{
			if(d[j]<N || G[j][cur]==0) continue;

			// j is reached first time
			// put it into queue
			que[++tail] = j;

			// update distance function
			numbs[N]--;
			d[j] = d[cur]+1;
			numbs[d[j]]++;
		}
	}
}

// augment the flow using predecessor list pi[]
int Augment()
{
	int i,j,tmp,width = INFi;

	// find the capacity of the path
	for(i=sink,j=pi[i];i!=source;i=j,j=pi[i])
	{
		tmp = G[j][i];
		if(tmp<width) width = tmp;
	}
	
	// augmenting
	for(i=sink,j=pi[i];i!=source;i=j,j=pi[i])
	{
		G[j][i]-=width; //F[j][i]+=width;
		G[i][j]+=width; //F[i][j]-=width;
	}
	return width;
}

// relabel and backtrack
int Retreat(int &cur)
{
	int tmp;
	int mind(N-1);

	FORj(1,N+1,1)
	{
		if(G[cur][j]>0 && d[j]<mind)
			mind = d[j];
	}

	tmp = d[cur];

	// relabel 
	numbs[ d[cur] ]--;
	d[cur] = 1+mind;
	numbs[ d[cur] ]++;

	// backtrack
	if(cur!=source) cur = pi[cur];

	// 
	return numbs[ tmp ];
}

// Main procedure
int MaxFlow_ISAP()
{
	int flow(0);

	rev_BFS(); //先吧所有顶点到sink的距离求出来

	//把所有点的当前边都设置成1
	FORi(1,N+1,1)
		CurrentNode[i] = 1;

	//
	int st = source;
	// the main cycle (while the source is not "far" from the sink)
	while(d[source]<N)
	{
		// start searching an admissible arc from the current arc
		int ds;
		for(ds=CurrentNode[st];ds<=N;ds++)
		{
			if(G[st][ds]>0 && d[st]==d[ds]+1)
				break;
		}
		// if the admissible arc is found
		if(ds<=N)
		{
			CurrentNode[st] = ds; // 把ds当成当前边的点
			pi[ds] = st; // ds is reachable from st;
			st = ds; // go forward

			if(st==sink)
			{
				flow+=Augment();
				st = source;
			}
		}
		else
		{
			CurrentNode[st] = 1;
			if( Retreat(st) == 0 )
				break;
		}

	}
	return flow;
}

int main()
{
	read;
	write;
	int a,b,c;
	char rt[4];
	while(scanf("%d %d %d %d",&N,&NP,&NC,&M)!=-1)
	{
		memset(G,0,sizeof(G));
		memset(F,0,sizeof(F));
		source = N+1;
		sink = N+2;

		getchar();
		while(M--)
		{
			scanf(" (%d,%d)%d",&a,&b,&c);
			//printf("边 %d %d %d\n",a,b,c);
			G[++a][++b]=c;
		}
		//为了找最大流,我们要添加一个新的源点和汇点 N和N+1
		//接下来是源点

		while(NP--)
		{
			scanf(" (%d)%d",&b,&c);
			//printf("源点 %d %d\n",b,c);
			G[N+1][++b] = c;
		}
		//接下来是汇点
		while(NC--)
		{
			scanf(" (%d)%d",&a,&c);
			G[++a][N+2] = c;
		}
		N+=2;
		// 图建好了
		
		printf("%d\n",MaxFlow_ISAP());
	}
	return 0;
}
posted @ 2011-03-16 15:35  AC2012  阅读(152)  评论(0编辑  收藏  举报