网络流的建模 !!有上下界的网络流!![运输问题2]

先来说连个比较简单的模型:

        多源多汇问题:

        对于这种问题,我们可以加一个超级源点和超级汇点,然后我们从超级源点到每一个源点都连一条上界为+00的边,同样也在每一个汇点到超级汇点都连一条上界为+00的边,这样跑一遍最大流即可。

        节点容量:

        我们可以把带容量的节点分裂成两个节点和一条边,边的容量和分裂前的点的容量相同。

下面我们这是开始说一下有上下界的情况

        ①无源汇有上下界的最大流。

        ②有源汇有上下界的最大流。

        ③有源汇有上下界的最小流。

①无源汇有上下界的最大流:

        建图模型:源点s,终点d。超级源点ss,超级终点dd。首先判断是否存在满足所有边上下界的可行流,方法可以转化成无源汇有上下界的可行流问题。怎么转换呢?

增设一条从d到s没有下界容量为无穷的边,那么原图就变成了一个无源汇的循环流图。接下来的事情一样,超级源点ss连i(du[i]>0),i连超级汇点(du[i]<0),

对(ss,dd)进行一次最大流,当maxflow等于所有(du[]>0)之和时,有可行流,否则没有。

当有可行流时,删除超级源点ss和超级终点dd,再对(s,d)进行一次最大流,此时得到的maxflow则为题目的解。为什么呢?因为第一次maxflow()只是求得所有满足下界的流量,而残留网络(s,d)路上还有许多自由流(没有和超级源点和超级汇点连接的边)没有流满,所有最终得到的maxflow=(第一次流满下界的流+第二次能流通的自由流)。

        ②有源汇有上下界的最大流:

        建图模型: 以前写的最大流默认的下界为0,而这里的下界却不为0,所以我们要进行再构造让每条边的下界为0,这样做是为了方便处理。对于每根管子有一个上界容量up和一个下界容量low,我们让这根管子的容量下界变为0,上界为up-low。可是这样做了的话流量就不守恒了,为了再次满足流量守恒,即每个节点"入流=出流”,我们增设一个超级源点st和一个超级终点sd。我们开设一个数组du[]来记录每个节点的流量情况。

du[i]=in[i](i节点所有入流下界之和)-out[i](i节点所有出流下界之和)。

当du[i]大于0的时候,st到i连一条流量为du[i]的边。

当du[i]小于0的时候,i到sd连一条流量为-du[i]的边。

最后对(st,sd)求一次最大流即可,当所有附加边全部满流时(即maxflow==所有du[]>0之和),有可行解。

 额。。。③暂时还没学。。。


运输问题2

【问题描述】
    一个工厂每天生产若干商品,需运输到销售部门进行销售。从产地到销地要经过某些城镇,有不同的路线可以行走,每条两城镇间的公路都有一定的流量限制。为了保证公路的运营效率,每条公路都有一个容量下界,也就是至少应有多少车辆通过。每条公路还有一个容量上界,也就是最多应有多少车辆通过。请你计算,在不考虑其它车辆使用公路的前提下,如何充分利用所有的公路,使产地运输到销地的商品最多,最多能运输多少商品。
【输入格式】
输入文件有若干行
第一行,一个整数n,表示共有n个城市(2<=n<=100),产地是1号城市,销地是n号城市
下面有n行,每行有2*n个数字。第p行第2*q-1,2*q列的数字表示城镇p与城镇q之间有无公路连接。数字为0表示无,大于0表示有公路,且这两个数字分别表示该公路流量的下界,上界。
【输出格式】
输出文件有一行
第一行,1个整数n,表示最大流量为n。
【输入输出样例】
输入文件名: maxflowb.in
6
0 0 1 3 0 10 0 0 0 0 0 0 
0 0 0 0 0 0 5 7 0 0 0 0
0 0 0 0 0 0 0 0 2 8 0 0
0 0 0 0 1 3 0 0 0 0 3 5
0 0 2 4 0 0 0 0 0 0 2 6
0 0 0 0 0 0 0 0 0 0 0 0
输出文件名:maxflowb.out
10

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,du[120]={0},map[120][120]={0},pre[120],level[120]={0},gap[120]={0},map1[120][120][3]={0},num=0,ans=0;
int ISAP(int x,int y){
	int u,v,i,minn,minm,maxn=0;
	memset(pre,-1,sizeof(pre));
	memset(level,0,sizeof(level));
	memset(gap,0,sizeof(gap));
	pre[x]=x;gap[0]=y;u=x;
	while(level[x]<y){
		for(v=1;v<=y;++v){
			if(map[u][v]>0&&level[v]+1==level[u]){
			    break;
			}
		}
		if(v<=y){
			pre[v]=u;u=v;
			if(v==y){
				minm=1000000000;
				for(i=v;i!=x;i=pre[i]){
					minm=min(minm,map[pre[i]][i]); 
				}
				maxn+=minm;
				for(i=v;i!=x;i=pre[i]){
					map[pre[i]][i]-=minm;
					map[i][pre[i]]+=minm;
				}
				u=x;
			}
		}
		else{
			minn=y;
			for(v=1;v<=y;++v){
				if(map[u][v]>0){
					minn=min(minn,level[v]);
				}
			}
			minn+=1;
			gap[level[u]]-=1;
			if(!gap[level[u]]) break;
			level[u]=minn;
			gap[level[u]]+=1;
			u=pre[u];
		}
	}
	return maxn;
}
int main()
{
	freopen("maxflowb.in","r",stdin);
	freopen("maxflowb.out","w",stdout);
	int i,j,x,y,m;
	scanf("%d",&n);
	for(i=1;i<=n;++i)
	  for(j=1;j<=n;++j){
	  	scanf("%d%d",&x,&y);
	  	map1[i][j][1]=x;
	  	map1[i][j][2]=y;
	  }
	for(i=1;i<=n;++i){
		x=0;y=0;
		for(j=1;j<=n;++j){
			x+=map1[j][i][1];
			y+=map1[i][j][1];
			map[i][j]=map1[i][j][2]-map1[i][j][1];
		}
		du[i]=x-y;
		if(du[i]>0) map[n+1][i]=du[i],num+=du[i];
		else map[i][n+2]=-du[i];
	}
	map[n][1]=1000000000;
	ans=ISAP(n+1,n+2);
    if(ans==num){
	    map[n][1]=0;
	    ans=ISAP(1,n);
	    printf("%d\n",ans);
	}
	else printf("0\n");
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值