poj2391(网络流+犀利建图)

1.思路

首先是想了半天硬是没想出来,看了这个解题报告才知道建的图

然后是敲代码又范了很多错误,果然是逻辑思维不严密,基本功不扎实啊!加//的地方都是范过错误的地方,调了我整整一天啊!

用时还挺多的,没办法,二分求值,顺便用来比较一下各种算法的效率!

预流推进的居然TLE!,看样子代码还是写得不够好,不过有点好的是,移植性好,只要图建好后直接上模板!

2.代码(dinic)


#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
#define N 420//双倍
#define M 500000//双倍
#define INF 100000000
#define MAX 1000000000000
struct Node{
    int u,v,next;
    int c;
};
struct Graph
{
    Node E[M];
    int first[N];
    int _V,_E,src,dest;
	int d[N];
	int num[N];
	int que[N],front,rear;
	int flow[N],cap[N];
	__int64 map[N][N];
	__int64 cost[N*N];
    void init(int n){
        _V=n,_E=0;
		src=0;dest=_V-1;
        memset(first,-1,4*_V);
    }
	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++;
	}
	bool bfs()
	{
		memset(d,-1,4*_V);
		d[src]=0;
		front=rear=0;
		que[rear++]=src;
		while(front!=rear){
			int u=que[front++];
			for(int e=first[u];e!=-1;e=E[e].next){
				int v=E[e].v;
				if(d[v]==-1&&E[e].c){
					d[v]=d[u]+1;
					que[rear++]=v;
				}
				if(d[dest]!=-1)return true;
			}
		}
		return false;
	}
	int dfs(int u,int cap)
	{
		if(u==dest)return cap;
		int rest=cap,aug;
		for(int e=first[u];e!=-1&&rest;e=E[e].next){
			int v=E[e].v,c=E[e].c;
			if(d[v]==d[u]+1&&c){
				aug=dfs(v,rest>c?c:rest);
				rest-=aug;
				E[e].c-=aug;
				E[e^1].c+=aug;
			}
		}
		return cap-rest;
	}
	int dinic(){
		int flow=0;
		while(bfs())flow+=dfs(src,INF);
		return flow;
	}
	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;
				int c=E[e].c;
                cout<<u<<' '<<v<<' ';
				printf("%d\n",c);
            }
        }
    }
	void build(int n,__int64 limit)
	{
		init(2*n+2);
		int i,j;
		for(i=1;i<=n;i++)
		{
			if(flow[i])
			{
				add(i,i+n,INF);
				add(src,i,flow[i]);
			}
			if(cap)add(i+n,dest,cap[i]);
		}
		for(i=1;i<=n;i++)
			for(j=i+1;j<=n;j++)
				if(map[i][j]<=limit)
					add(i,j+n,INF),add(j,i+n,INF);//
	}
	__int64 solve(int n,int m)
	{
		int tot=0,tot2=0;
		int i,j,k;
		for(i=1;i<=n;i++)
		{
			scanf("%d%d",flow+i,cap+i);
			tot+=flow[i];
			tot2+=cap[i];
		}
		for(i=1;i<=n;i++)
		{
			fill(map[i],map[i]+1+n,MAX);
			map[i][i]=0;
		}
		
		int u,v,c;
		for(i=1;i<=m;i++)
		{
			scanf("%d%d%d",&u,&v,&c);
			if(c<map[u][v])map[u][v]=map[v][u]=c;
		}
		if(tot>tot2)return -1;
		for(k=1;k<=n;k++)
		{
			for(i=1;i<=n;i++)
			{
				for(j=1;j<=n;j++)
				{
					if(i==j)continue;
					__int64 t=map[i][k]+map[k][j];
					if(t<map[i][j])map[i][j]=t;	
				}
			}
		}
		int cnt;
		cost[cnt=1]=0;//
		
		for(i=1;i<=n;i++)
		{
			for(j=i+1;j<=n;j++)
				if(map[i][j]<MAX)cost[cnt++]=map[i][j];//
		}
		sort(cost+1,cost+cnt);
		for(i=1,j=1;i<cnt;i++){
			if(cost[i]==cost[j-1])continue;
			cost[j++]=cost[i];
		}
		int l=0,r=j-1,mid;
		while(l<=r)
		{
			mid=(l+r)>>1;
			build(n,cost[mid]);	
			if(dinic()==tot)
			{
				r=mid;//
				if(l==r)return cost[r];
			}
			else l=mid+1;
		}
		return -1;//
	}
}net;

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

2.sap


#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
#define N 420//双倍
#define M 500000//双倍
#define INF 100000000
#define MAX 1000000000000
struct Node{
    int u,v,next;
    int c;
};
struct Graph
{
    Node E[M];
    int first[N];
    int _V,_E,src,dest;
	int d[N];
	int num[N];
	int pre[N],cur,next;
	int flow[N],cap[N];
	__int64 map[N][N];
	__int64 cost[N*N];
    void init(int n){
        _V=n,_E=0;
		src=0;dest=_V-1;
        memset(first,-1,4*_V);
    }
	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++;
	}
	inline bool advance(){
		for(int e=first[cur];e!=-1;e=E[e].next){
			if(d[cur]==d[E[e].v]+1&&E[e].c){
				pre[cur=E[e].v]=e;
				return true;
			}
		}
		return false;
	}
	inline int relable(){
		int mini=_V-1;
		for(int e=first[cur];e!=-1;e=E[e].next)if(E[e].c&&d[E[e].v]<mini)mini=d[E[e].v];
		return mini+1;
	}
	int sap(){
		memset(d,-1,4*_V);//!!!
		memset(num,0,4*_V);//
		pre[src]=-1;//!!!
		int flow=0,aug;

		while(d[src]!=_V){
			cur=src;
			while(cur!=dest){
				if(advance())continue;
				int lable=relable();
				num[d[cur]]--;num[d[cur]=lable]++;
				if( !num[d[cur]] || d[src]==_V )return flow;	
				if(cur!=src)cur=E[pre[cur]].u;//满足可行弧定义
			}
			aug=INF;
			int e=pre[dest],aug=INF;
			while(e!=-1)aug=aug<E[e].c?aug:E[e].c,e=pre[E[e].u];
			flow+=aug;e=pre[dest];
			while(e!=-1)E[e].c-=aug,E[e^1].c+=aug,e=pre[E[e].u];
		}
		return flow;
	}
	void build(int n,__int64 limit)
	{
		init(2*n+2);
		int i,j;
		for(i=1;i<=n;i++)
		{
			if(flow[i])
			{
				add(i,i+n,INF);
				add(src,i,flow[i]);
			}
			if(cap)add(i+n,dest,cap[i]);
		}
		for(i=1;i<=n;i++)
			for(j=i+1;j<=n;j++)
				if(map[i][j]<=limit)
					add(i,j+n,INF),add(j,i+n,INF);//
	}
	__int64 solve(int n,int m)
	{
		int tot=0,tot2=0;
		int i,j,k;
		for(i=1;i<=n;i++)
		{
			scanf("%d%d",flow+i,cap+i);
			tot+=flow[i];
			tot2+=cap[i];
		}
		for(i=1;i<=n;i++)
		{
			fill(map[i],map[i]+1+n,MAX);
			map[i][i]=0;
		}
		
		int u,v,c;
		for(i=1;i<=m;i++)
		{
			scanf("%d%d%d",&u,&v,&c);
			if(c<map[u][v])map[u][v]=map[v][u]=c;
		}
		if(tot>tot2)return -1;
		for(k=1;k<=n;k++)
		{
			for(i=1;i<=n;i++)
			{
				for(j=1;j<=n;j++)
				{
					if(i==j)continue;
					__int64 t=map[i][k]+map[k][j];
					if(t<map[i][j])map[i][j]=t;	
				}
			}
		}
		int cnt;
		cost[cnt=1]=0;//
		
		for(i=1;i<=n;i++)
		{
			for(j=i+1;j<=n;j++)
				if(map[i][j]<MAX)cost[cnt++]=map[i][j];//
		}
		sort(cost+1,cost+cnt);
		for(i=1,j=1;i<cnt;i++){
			if(cost[i]==cost[j-1])continue;
			cost[j++]=cost[i];
		}
		int l=0,r=j-1,mid;
		while(l<=r)
		{
			mid=(l+r)>>1;
			build(n,cost[mid]);	
			if(sap()==tot)
			{
				r=mid;//
				if(l==r)return cost[r];
			}
			else l=mid+1;
		}
		return -1;//
	}
}net;

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


3.预流推进


是代码写厥了?

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
using namespace std;
#define N 420//双倍
#define M 500000//双倍
#define INF 100000000
#define MAX 1000000000000
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;

	int flow[N],cap[N];
	__int64 map[N][N];
	__int64 cost[N*N];
    void init(int n){
        _V=n,_E=0;
		src=0;dest=_V-1;
        memset(first,-1,4*_V);
    }
	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;
                }
            }
        }
    }
	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;
			}
		}
	}
	void build(int n,__int64 limit)
	{
		init(2*n+2);
		int i,j;
		for(i=1;i<=n;i++)
		{
			if(flow[i])
			{
				add(i,i+n,INF);
				add(src,i,flow[i]);
			}
			if(cap)add(i+n,dest,cap[i]);
		}
		for(i=1;i<=n;i++)
			for(j=i+1;j<=n;j++)
				if(map[i][j]<=limit)
					add(i,j+n,INF),add(j,i+n,INF);//
	}
	__int64 solve(int n,int m)
	{
		int tot=0,tot2=0;
		int i,j,k;
		for(i=1;i<=n;i++)
		{
			scanf("%d%d",flow+i,cap+i);
			tot+=flow[i];
			tot2+=cap[i];
		}
		for(i=1;i<=n;i++)
		{
			fill(map[i],map[i]+1+n,MAX);
			map[i][i]=0;
		}
		
		int u,v,c;
		for(i=1;i<=m;i++)
		{
			scanf("%d%d%d",&u,&v,&c);
			if(c<map[u][v])map[u][v]=map[v][u]=c;
		}
		if(tot>tot2)return -1;
		for(k=1;k<=n;k++)
		{
			for(i=1;i<=n;i++)
			{
				for(j=1;j<=n;j++)
				{
					if(i==j)continue;
					__int64 t=map[i][k]+map[k][j];
					if(t<map[i][j])map[i][j]=t;	
				}
			}
		}
		int cnt;
		cost[cnt=1]=0;//
		
		for(i=1;i<=n;i++)
		{
			for(j=i+1;j<=n;j++)
				if(map[i][j]<MAX)cost[cnt++]=map[i][j];//
		}
		sort(cost+1,cost+cnt);
		for(i=1,j=1;i<cnt;i++){
			if(cost[i]==cost[j-1])continue;
			cost[j++]=cost[i];
		}
		int l=0,r=j-1,mid;
		while(l<=r)
		{
			mid=(l+r)>>1;
			build(n,cost[mid]);	
			if(preFlowPush()==tot)
			{
				r=mid;//
				if(l==r)return cost[r];
			}
			else l=mid+1;
		}
		return -1;//
	}
}net;

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值