HDU 3157 有源汇上下界最小流

56 篇文章 0 订阅
9 篇文章 0 订阅

可以直接无视那长长的段落。。

+ 表示是源点, - 表示是汇点

1,2,3,,,...n 表示n个节点

要求是否存在满足 下界限制的最小的流

如果不存在输出 impossible


最下界最小流。。 看 周源  《一种简易的方法求解流量有上下界的网络中网络流问题》  里面介绍的时候是讲用二分思想。。但是 = =有更简单的

先求是否存在可行流。。

则判断 无源无汇情况下是否存在可行流,  则用无源无汇的建图方式

....

src0,dest0  为 图中给出的 源点与汇点,  s,t为新增的附加源点与汇点

1. 构造附加网络(不添加[t,s]边) 
2. 对s、t求最大流    

---- 上面为无源无汇建图方式 ,  src0,dest0 是 + 与 - 那两个题目中所给的源点跟汇点,所以要放到无源无汇中跑

求出此时的 最大流 sum1

之后
3. 添加[ dest0 ,src0 ]  无穷大 这条边 
4. 对s、t  再次求最大流 

此时得到最大流  sum2


5. 若s、t  的 sum1 + sum2 == 无源无汇时的满流,则[t,s]的流量就是最小流 

从残留网络中输出答案即可


//tpl  
//ipqhjjybj_tpl.h  
//header.h  

/*
src0,dest0  为 图中给出的 源点与汇点,  s,t为新增的附加源点与汇点
1. 构造附加网络(不添加[t,s]边) 
2. 对s、t求最大流    
---- 上面为无源无汇建图方式 ,  src0,dest0 是 + 与 - 那两个题目中所给的源点跟汇点,所以要放到无源无汇中跑
求出此时的 最大流 sum1
之后
3. 添加[ dest0 ,src0 ]  无穷大 这条边 
4. 对s、t  再次求最大流 
此时得到最大流  sum2

5. 若s、t  的 sum1 + sum2 == 无源无汇时的满流,则[t,s]的流量就是最小流 
从残留网络中输出答案即可

 */
#include <cstdio>  
#include <cstdlib>  
#include <map>  
#include <set>  
#include <algorithm>  
#include <cstring>  
#include <iostream>  
#include <vector>  
#include <string>  
#include <queue>  
#include <sstream>  
#include <math.h>  
  
#define mp(x,y) make_pair(x,y)  
#define pii pair<int,int>  
#define pLL pair<long long ,long long>  
#define pb(x) push_back(x)  
#define rep(i,j,k) for(int i = j; i < k;i++)  
  
#define MAX(x,a)  x=((x)<(a))?(a):(x);  
#define MIN(x,a)  x=((x)>(a))?(a):(x);  
  
using namespace std;  
  
const int N = 500;  
int n,m,tot;  
int s,t;  
int sum;  
struct node{  
    int u,v,w,next;  
    node(){}  
    node(int _u,int _v,int _w,int _next){  
        u=_u,v=_v,w=_w,next=_next;  
    }  
}edge[N*N];  
int head[N],cur[N],dis[N];  
int pre[N],gap[N],aug[N];  
const int oo=0x3f3f3f3f;  
void addEdge(int u,int v,int w){  
    edge[tot]=node(u,v,w,head[u]);  
    head[u]=tot++;  
    edge[tot]=node(v,u,0,head[v]);  
    head[v]=tot++;  
}  
  
int SAP(int s,int e,int n){  
    int max_flow=0,v,u=s;  
    int id,mindis;  
    aug[s]=oo;  
    pre[s]=-1;  
    memset(dis,0,sizeof(dis));  
    memset(gap,0,sizeof(gap));  
    gap[0]=n;  
  
    for(int i=0;i <= n;i++)  
        cur[i]=head[i];  
  
    while(dis[s]<n){  
        if(u==e){  
            max_flow += aug[e];  
            for(v=pre[e]; v!=-1; v=pre[v]){  
                int ed=cur[v];  
                edge[ed].w -= aug[e];  
                edge[ed^1].w += aug[e];  
                aug[v]-=aug[e];  
                if(edge[ed].w==0) u=v;  
            }  
        }  
        bool flag=false;  
        for(id=cur[u]; id!=-1;id=edge[id].next){  
            v=edge[id].v;  
            if(edge[id].w > 0 && dis[u]==dis[v]+1){  
                flag=true;  
                pre[v]=u;  
                cur[u]=id;  
                aug[v]=min(aug[u],edge[id].w);  
                u=v;  
                break;  
            }  
        }  
        if(flag==false){  
            if(--gap[dis[u]] == 0) break;   
            int mindis=n;  
            for(id=head[u]; id!=-1; id=edge[id].next){  
                v=edge[id].v;  
                if(edge[id].w>0 && dis[v] < mindis){  
                    mindis = dis[v];  
                    cur[u]=id;  
                }  
            }  
            dis[u] = mindis + 1;  
            gap[dis[u]]++;  
            if(u!=s)u=pre[u];  
        }  
    }  
    return max_flow;  
}  

char s1[10],s2[10];
int in[N];
int max_flow;
int getNum(char fs[]){
	if(fs[0] == '+')return s;
	else if(fs[0] == '-') return t;
	else return atoi(fs);
}
int solve(){
	int i,src0,dest0;
	src0 = s, dest0 = t;
	s = n+2, t = n+3;

	rep(i,0,dest0+1)
		if(in[i]>0) addEdge(s,i,in[i]);
		else if(in[i]<0) addEdge(i,t,-in[i]),max_flow += -in[i];
	int ans1 = SAP(s,t,n+4);

	addEdge(dest0,src0,oo);
	int kk = SAP(s,t,n+4);
	if(kk+ans1 == max_flow)
		return edge[tot-1].w;
	else return -1;
}
int main(){
	while(scanf("%d %d",&n,&m)!=EOF){
		if(n==0 && m==0) break;
		memset(head,-1,sizeof(head));
		memset(in,0,sizeof(in));
		s = sum = tot =0; t=n+1;
		max_flow = 0;
		rep(i,0,m){
			int l,r,w;
			scanf("%s %s %d",s1,s2,&w);
			l = getNum(s1),r = getNum(s2); 
			// printf("l=%d r=%d w=%d\n",l,r,w);
			addEdge(l,r,oo);
			in[r]+=w, in[l]-=w;
		}int ans=0;
		if((ans=solve())>=0) printf("%d\n",ans);
		else puts("impossible");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值