poj1459(网络流)

昨天学的最高标号预流推进

  没看别人代码敲的,后来有一个BUG,参考了一下别人的代码:http://www.cnblogs.com/Open_Source/archive/2010/08/03/1904898.html

能参考的资料太少了,基本上是连蒙带猜写的代码,还好之前学过SAP,网络流的算法原理好像都是基于最大流最小割定理的,组合数学上都有详细的证明!

参考:

1.刘汝佳《算法艺术与信息学竞赛》P321

2.http://trp.jlu.edu.cn/software/net/lssx/4/4.41.htm

总体感觉就像打乒乓球:推过去又送回来!

代码:(注意越界!)

#include<cstdio>
#include<iostream>

using namespace std;
//   freopen("data.in","r",stdin);

#include<queue>
#include<cstring>
#define N 105
#define M (N*N+210)*2//double
#define INF 4000000000
int d[N];
struct cmp
{
    bool operator()(const int &u,const int &v)const
    {
        return d[u]<d[v];
    }
};
struct Node
{
    int u,v,next;
    int c;
};
struct Graph
{
    Node E[M];
    int first[N];
    int _V,_E,src,dest;
    __int64 rest[N];
    int in[N];
    priority_queue<int,vector<int>,cmp> active;
	
    void initial(int n)
    {
        _V=n+2;_E=0;
        src=n,dest=n+1;
        memset(first,-1,4*_V);//!!
    }
    void build(int n,int np,int nc,int m)
    {
        initial(n);
        int i,u,v,c;
        for(i=0; i<m; i++)
        {
            scanf("%*[^(](%d,%d)%d",&u,&v,&c);
            if(u==v)continue;
            add(u,v,c);
        }
        for(i=0; i<np; i++)
        {
            int u,c;
            scanf("%*[^(](%d)%d",&u,&c);
            add(src,u,c);
        }
        for(i=0; i<nc; i++)
        {
            int u,c;
            scanf("%*[^(](%d)%d",&u,&c);
            add(u,dest,c);
        }
    }
    void add(int u,int v,int c){
        E[_E].u=u,E[_E].v=v,E[_E].c=c,E[_E].next=first[u],first[u]=_E,_E++;
		E[_E].u=v,E[_E].v=u,E[_E].c=0,E[_E].next=first[v],first[v]=_E,_E++;//
    }
    void calHeight(){
        memset(d,-1,sizeof(d));
        d[dest]=0;
		int que[N],front,rear;
        front=rear=0;
        que[rear++]=dest;
        while(front!=rear){
            int v=que[front++],u;
            for(int e=first[v]; e!=-1; e=E[e].next){
                u=E[e].v;
                if(d[u]==-1){
                    d[u]=d[v]+1;
                    que[rear++]=u;
                }
            }
        }
        d[src]=_V;//!!
    }
	void preprocess(){
        for(int i=0;i<_V;i++)rest[i]=in[i]=0;
        rest[src]=INF;active.push(src);
    }
    inline void push(int u){
        for(int e=first[u]; e!=-1&&rest[u]; e=E[e].next){
			int v=E[e].v,c=E[e].c;
            if(d[E[e].v]+1==d[u]&&E[e].c){
				int aug=rest[u]<c?rest[u]:c;//!!
				rest[v]+=aug,rest[u]-=aug,E[e].c-=aug,E[e^1].c+=aug;
				if(!in[v]&&v!=dest&&v!=src){
					active.push(v);
					in[v]=true;
				}
			}
        }
	}
	inline bool relable(int u){
		d[u]=_V-1;
		for(int e=first[u]; e!=-1; e=E[e].next)if(E[e].c&&d[u]>d[E[e].v])d[u]=d[E[e].v];
		d[u]++;
		return d[u]!=_V;
	}
	__int64 preFlowPush()
	{
		calHeight();
		preprocess();
		while(!active.empty()){//!!不记录s,t
			int u=active.top();
			push(u);//从点u进行推流
			if(rest[u]&&relable(u))continue;//可以继续推流
			active.pop();in[u]=false;//否则弹出队列
		}
		return rest[dest];
	}
	void display(){
		for(int i=0; i<_V; i++){
			for(int e=first[i]; e!=-1; e=E[e].next){
				int u=E[e].u,v=E[e].v,c=E[e].c;
				cout<<u<<' '<<v<<' '<<c<<endl;
			}
		}
	}
} net;

int main()
{
#ifndef ONLINE_JUDGE
	freopen("data.in", "r", stdin);
#endif
	int n,np,nc,m;
	while(cin>>n)
	{
		cin>>np>>nc>>m;
		net.build(n,np,nc,m);
		//     net.display();
		printf("%I64d\n",net.preFlowPush());
	}
	return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值