3469(2)

/*
	能想到的优化都加了
*/

// 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 20010
#define MAXM 510000
int N,M;
int source,sink;
struct node1
{
	int e;
	int next;
	int residual;
};

node1 mem[MAXM];
int G[MAXN];    // 正邻接表,正边和反向边在内存上差一 
//node1 Rmem[MAXM]; 
//int RG[MAXN];   // 反邻接表,这样我们就能快速的知道正边和反边的地理位置了

int dis[MAXN];       // 到汇点的距离

int stk[MAXN],top;   // 其实就是个栈嘛
int stkmin[MAXN],mtop; //到当前为止的最小值
int stkdx[MAXN],dtop;  //记录最小值对应索引值
int stkver[MAXN],vtop; //记录最小值对应的顶点


int father[MAXN];    // 记录每个顶点的父亲
int curpos[MAXN];    // 每个点需要开始的位置
int laynum[MAXN];    // 每层的顶点个数
int que[MAXN];       // BFS用


int Augment()
{
	int minp = stkmin[mtop-1];

	// 找到做小边后,然后修改路径了
	FORi(0,top,1)
	{
		mem[stk[i]].residual -= minp;
		mem[(stk[i]&1)?(stk[i]-1):(stk[i]+1)].residual += minp;
		stkmin[i+1] -= minp;
	}

	return minp;
}

int Retreat(int &cur)
{
	// 找出所有儿子的最小值
	int tmp;
	int mind(N-1);
	int mdx = G[cur];
	while(mdx!=-1)
	{
		if( mem[mdx].residual>0 && dis[ mem[mdx].e ]<mind)
			mind = dis[ mem[mdx].e ];
		mdx = mem[mdx].next;
	}

	tmp = dis[cur];

	// relabel
	laynum[ dis[cur] ]--;
	dis[cur] = 1+mind;
	laynum[ dis[cur] ]++;
	
	//backtrack
	if(cur!=source) 
	{
		cur = father[cur];
		top --;
		mtop--;
		dtop--;
		vtop--;
	}

	return laynum[ tmp ];
}

int MaxFlow_ISAP()
{
	int flow(0);

	//BFS(); // 距离求出来了
	//memset(laynum,0,sizeof(laynum));
	//memset(dis,(int)1,sizeof(dis));
	fill(laynum,laynum+N+3,0);
	fill(dis,dis+N+3,1);

	dis[source] = 2;
	laynum[2]++;
	dis[sink] =0 ;
	laynum[0]++;
	
	laynum[1] = N;

	// 在加一个什么优化呢??

	memcpy(curpos,G,sizeof(G));

	stkmin[0] = INFi;
	mtop = 1;
	stkdx[0] = -1;
	dtop = 1;
	stkver[0] = -1;
	vtop = 1;

	top = 0;

	fill(father,father+N+3,-1);
	int st = source;
	while( dis[source]<N )
	{
		//
		int ds=-1,dsmx,mdx;
		mdx = curpos[st];
		while(mdx!=-1)
		{
			int v = mem[mdx].e;
			if( mem[mdx].residual>0 && dis[st]==dis[v]+1 )
			{
				ds = v;
				dsmx = mdx;
				break;
			}

			mdx = mem[mdx].next;
		}

		if(ds!=-1) //如果找到了
		{
			curpos[st] = dsmx;
			stk[top++] = dsmx;
			
			if(mem[dsmx].residual<stkmin[mtop-1])
			{
				stkmin[mtop] = mem[dsmx].residual;
				stkdx[dtop] = mtop;   // 记录栈的编号,以方便回来
				stkver[vtop] = st;    // 而其才是真正的记录该边的起点的
				mtop++;
				dtop++;
				vtop++;
			}
			else
			{
				stkmin[mtop] = stkmin[mtop-1]; 
				mtop++;
				stkdx[dtop] = stkdx[dtop-1]; 
				dtop++;
				stkver[vtop] = stkver[vtop-1]; 
				vtop++;
			}

			father[ds] = st;
			st = ds;

			if(st==sink)
			{
				// 此处要优化,当到达汇点的时候,我们要返回至最小边处

				flow += Augment();
				
				st = stkver[vtop-1];
				top = stkdx[dtop-1]-1;
				mtop = stkdx[dtop-1];
				vtop = stkdx[dtop-1];
				dtop = stkdx[dtop-1];
			}
		}
		else //如果没有找到
		{
			curpos[st] = G[st];
			if( Retreat(st) == 0 )
				break;
		}
	}

	return flow;
}

int main()
{
	read;
	write;
	int a,b,c,dx;

	while(scanf("%d %d",&N,&M)!=-1)
	{
		source = N+1;
		sink = N+2;
		dx = 0;
	
		fill(G,G+N+3,-1);


		FORi(1,N+1,1)
		{
			scanf("%d %d",&a,&b);
			//Add_edge(dx++,source,i,a);
			////Add_edge(dx++,i,source,a);
			//Add_edge(dx++,i,sink,b);
			//Add_edge(dx++,sink,i,b);

			mem[dx].e = i;
			mem[dx].residual = a;
			mem[dx].next = G[source];
			G[source] = dx++;

			mem[dx].e = source;
			mem[dx].residual = a;
			mem[dx].next = G[i];
			G[i] = dx++;

			mem[dx].e = sink;
			mem[dx].residual = b;
			mem[dx].next = G[i];
			G[i] = dx++;

			mem[dx].e = i;
			mem[dx].residual = b;
			mem[dx].next = G[sink];
			G[sink] = dx++;
		}
		FORi(0,M,1)
		{
			scanf("%d %d %d",&a,&b,&c);
			//Add_edge(dx++,a,b,c);
			
			mem[dx].e = b;
			mem[dx].residual = c;
			mem[dx].next = G[a];
			G[a] = dx++;
			
			//Add_edge(dx++,b,a,c);
			mem[dx].e = a;
			mem[dx].residual = c;
			mem[dx].next = G[b];
			G[b] = dx++;
		}
		N+=2;
		printf("%d\n",MaxFlow_ISAP());
		
	}
	return 0;
}

posted @ 2011-03-16 15:33  AC2012  阅读(130)  评论(0编辑  收藏  举报