有上下界限制的网络流

定理及模型参见《

详细构图过程及证明参见《Amer图论总结》

1.最简单的是求无源汇点的图的可行流。

若存在可行流,由于每条弧的流量都要大于下限,因此可以将每条弧拆为流量为low的和一条流量为up-low的,称前者为必要弧增加一个附加源x,一个附加汇y,每条有向必要弧(u, v),添加(u, y)(x, v),容量为low。这样就建立了一个等价的网络。附加源x到附加汇y的最大流,能使得x的出弧或者y的入弧都满,充要于原图有可行流。

sgu194 reactor cooling

如果汇源,汇向源连一条没有上下限的边(确保流量平衡条件),于是就转换成了上述问题。

poj2396 budget  代码:点击查看源代码

2.最大流

求完可行流后upflow将附加源和附加汇及关联的弧,残余网络中求解某个流flow,那么upflow+flow仍然是原图的一个可行流,因此对残留网络再求一次最大流就得到了原图的最大流。

zoj3229 shoot the bullet 代码:点击查看源代码

3.最小流

网上看过很多做啊是延残留网络逆向增广求最小流,貌似这样有bug,还是二分枚举原图源点到汇点的流量上届,然后通过验证是否存在可行流比较靠谱,也比较好理解。

sgu176 flow construction 代码:点击查看源代码

4.有上下界的最小费用流

由于上下界只限制流量对费用没太多影响,因此按照以上方法构图应该就可以,但是没有见过这一类题目,也不敢妄下断言。。

与普通最大流相同部分之处就不贴了。。。

int getsap(int s, int t) {
			if (s == t)
				return inf;
			this.s = s;
			this.t = t;
			Arrays.fill(h, 0);
			Arrays.fill(vh, 0);
			//flow 不需要在此清零!!!
			int ans = 0;
			while (h[s] != n)
				ans += sap(s, inf);
			return ans;
		}
		void addcap(int a, int b, int low, int up) {
			buf[len] = new node(b, low, up, E[a]);
			E[a] = len++;
			buf[len] = new node(a, 0, 0, E[b]);
			E[b] = len++;
			sumin[b] += low;
			sumout[a] += low;// init()时清零
		}
		void popcap(int i, int j) {
			E[j] = buf[E[j]].ne;
			E[i] = buf[E[i]].ne;
			len -= 2;
		}
		int bin(int s,int t,int k){//源点汇点之间上限为k时的最大流
			addcap(t, s, 0, k);
			for (int i = 0; i < len; i++)
				buf[i].flow = 0;
			int ans=getsap(n-2,n-1);
			popcap(s,t);
			return ans;
		}
		int solve(int s, int t,int mn) {
			int total = 0;
			int ss = n, tt = n + 1;
			for (int i = 0; i < n; i++) {
				addcap(i, tt, 0, sumout[i]);
				addcap(ss, i, 0, sumin[i]);
				total += sumin[i];
			}
			n += 2;
			int ans =bin(s,t,inf);
			if (ans != total) 
				return -1;//不存在可行流
			/*求解最小流
			int left=0,right=total,mid;
			while(left<=right){
				mid=(left+right)>>1;
	            int temp=bin(s,t,mid);
			    if(temp==total)
			    {
			    	ans=mid;
			    	right=mid-1;
			    }
			    else
			    	left=mid+1;
			}
			bin(s,t,ans);// ans is the mininum flow
			*/
			n -= 2;
			for (int i = n - 1; i >= 0; i--)
			{
				popcap(ss, i);
				popcap(i, tt);
			}
			getsap(s,t);
			ans=0;
			for(int i=0;i<len;i+=2){
				buf[i].flow+=buf[i].low;
				if(buf[i].be==t)
					ans+=buf[i].flow;
			}
			return ans;
		}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值