有下界最大流问题

(1)、无源无汇有容量下界的可行流问题;

建立附加源s和附加汇t,然后对弧进行改造:首先添加弧t->s容量为无穷大;然后把每条弧(u,v)拆成3条:s->v(容量为u,v的下界),u->t(容量为u,v下届),u ->v(容量为u,v上界减去u,v下界)

求改造后的网络的最大流即可。当且仅当所有附加弧(与s和t相连的边)满载时原网络有可行流。且原网络中每条边(u,v)的流量的等于改造后的网络中(u,v)的流量加上(u,v)的下界;

ZOJ2314 无源无汇可行流模板题目;

#include<cstdio>  
#include<cstring>  
#include<cmath>  
#include<cstdlib>  
#include<climits>  
#include<cctype>  
#include<iostream>  
#include<algorithm>  
#include<queue>  
#include<vector>  
#include<map>  
#include<set>  
#include<string>  
#include<stack>  
#define ll long long  
#define MAX 500  
#define eps 1e-8  
#define INF 100000000  
  
using namespace std;  

struct Node{
	int l,c;
}F[MAX][MAX];
  
struct Edge{  
    int from, to,cap,flow;  
};  
  
vector<int>G[MAX],T[MAX];  //T用来记录G的转置,用于下面逆向bfs遍历图  
vector<Edge>edges;  
  
int n;  
  
void init(){  
    for (int i=0; i<MAX; i++){  
        G[i].clear();  
        T[i].clear();  
    }  
    edges.clear();  
}  
  
void addEdge(int from, int to, int cap){  
    edges.push_back((Edge){from,to,cap,0});  
    edges.push_back((Edge){to,from,0,0});  
    int k = edges.size();  
    G[from].push_back(k-2);  
    G[to].push_back(k-1); 
	T[to].push_back(from); 
}  
  
int d[MAX];  
  
void bfs(int s, int t){  
    bool vis[MAX];  
    queue<int>q;  
    memset(vis,false,sizeof(vis));  
    q.push(s);  
    d[s] = 0;  
    vis[s] = true;  
    while (!q.empty()){  
        int u = q.front();  
        q.pop();  
        for (int i=0; i<T[u].size(); i++){  
            int v = T[u][i];  
            if (!vis[v]){  
                d[v] = d[u] + 1;  
                vis[v]  =  true;  
                q.push(v);  
            }  
        }  
    }  
}  
  
int p[MAX],num[MAX],cur[MAX];  
  
int Augment(int s, int t){  
    int x = t, a = INF;  
    while (x != s){  
        Edge& e = edges[p[x]];  
        a = min(a,e.cap - e.flow);  
        x = edges[p[x]].from;  
    }  
    x = t;  
    while (x != s){  
        edges[p[x]].flow += a;  
        edges[p[x]^1].flow -= a;  
        x = edges[p[x]].from;  
    }  
    return a;  
}  
  
int Maxflow(int s, int t){  
    int flow = 0;  
    bfs(t,s);                //逆向bfs    
    memset(num,0,sizeof(num));  
    for (int i=0; i<=n; i++) num[d[i]]++;   //注意此处i应该对应节点编号   
    int x = s;  
    memset(cur,0,sizeof(cur));  
    while (d[s] < n+1){          //此处d[s]应下于节点数量
        if (x == t){  
            flow += Augment(s,t);  
            x = s;  
        }  
        int ok = 0;  
        for (int i=cur[x]; i<G[x].size(); i++){  
            Edge& e = edges[G[x][i]];  
            if (e.cap > e.flow && d[x] == d[e.to] + 1){  
                ok = 1;  
                p[e.to] = G[x][i];  
                cur[x] = i;  
                x = e.to;  
                break;  
            }  
        }  
        if (!ok){  
            int m = n-1;  
            for (int i=0; i<G[x].size(); i++){  
                Edge& e = edges[G[x][i]];  
                if (e.cap > e.flow) m = min(m,d[e.to]);  
            }  
            if (--num[d[x]] == 0) break;       //gap优化,能使时间复杂度降低100倍左右  
            num[d[x] = m+1]++;  
            cur[x] = 0;  
            if (x != s) x = edges[p[x]].from;  
        }  
    }  
    return flow;  
}  

int mark[MAX][MAX];

int main(){
	int cas,m;
	scanf("%d",&cas);
	while (cas--){
		scanf("%d%d",&n,&m);
		int x,y,l,c;
		init();
		int SS = 0,TT = n+1;
		addEdge(TT,SS,INF);               
		memset(mark,0,sizeof(mark));
		for (int i=0; i<m; i++){        //拆边
			scanf("%d%d%d%d",&x,&y,&l,&c);
			mark[x][y] = 1;
			F[x][y] = (Node){l,c};
			addEdge(x,y,c-l);
			addEdge(x,TT,l);
			addEdge(SS,y,l);
		}
		n = TT;
		int ans = Maxflow(SS,TT);
	//	printf("ans = %d\n",ans);
		int ok = 1;
		for (int i = 0; i<edges.size(); i++){    //判断是否有可行流
			Edge e = edges[i];
			if ((e.from == SS || e.to == TT) && e.cap > e.flow){
				ok = 0;
				break;
			}
		}
		if (ok){
			printf("YES\n");
			
			for (int i=0; i<edges.size(); i++){    //求解每条边的流量
				Edge e =edges[i];
				if (e.flow >= 0 && mark[e.from][e.to] && e.from != SS && e.to != TT)
					printf("%d\n",e.flow + F[e.from][e.to].l);
			}
		}
		else printf("NO\n");
		if (cas) printf("\n");
	}
	return 0;
}


有源有汇有上下界的最大流问题;

设源点为s,t;建立附加源点SS,附加汇点TT;

首先连边t->s,容量为无穷大使其转化为无源无汇问题;在对网络中的每一条边(u,v)按照无源无汇中的方法拆成三条边;

最后求一下SS->TT的最大流;可行流存在的条件以及原网络中的每条边的流量同上;

poj2396 有源有汇有上下界的最大流问题;

#include<cstdio>  
#include<cstring>  
#include<cmath>  
#include<cstdlib>  
#include<climits>  
#include<cctype>  
#include<iostream>  
#include<algorithm>  
#include<queue>  
#include<vector>  
#include<map>  
#include<set>  
#include<string>  
#include<stack>  
#define ll long long  
#define MAX 500  
#define eps 1e-8  
#define INF 100000000  
  
using namespace std;  

struct Node{
	int l,c;
}F[MAX][MAX];
  
struct Edge{  
    int from, to,cap,flow;  
};  
  
vector<int>G[MAX],T[MAX];  //T用来记录G的转置,用于下面逆向bfs遍历图  
vector<Edge>edges;  
  
int n;  
  
void init(){  
    for (int i=0; i<MAX; i++){  
        G[i].clear();  
        T[i].clear();  
    }  
    edges.clear();  
}  
  
void addEdge(int from, int to, int cap){  
    edges.push_back((Edge){from,to,cap,0});  
    edges.push_back((Edge){to,from,0,0});  
    int k = edges.size();  
    G[from].push_back(k-2);  
    G[to].push_back(k-1); 
	T[to].push_back(from); 
}  
  
int d[MAX];  
  
void bfs(int s, int t){  
    bool vis[MAX];  
    queue<int>q;  
    memset(vis,false,sizeof(vis));  
    q.push(s);  
    d[s] = 0;  
    vis[s] = true;  
    while (!q.empty()){  
        int u = q.front();  
        q.pop();  
        for (int i=0; i<T[u].size(); i++){  
            int v = T[u][i];  
            if (!vis[v]){  
                d[v] = d[u] + 1;  
                vis[v]  =  true;  
                q.push(v);  
            }  
        }  
    }  
}  
  
int p[MAX],num[MAX],cur[MAX];  
  
int Augment(int s, int t){  
    int x = t, a = INF;  
    while (x != s){  
        Edge& e = edges[p[x]];  
        a = min(a,e.cap - e.flow);  
        x = edges[p[x]].from;  
    }  
    x = t;  
    while (x != s){  
        edges[p[x]].flow += a;  
        edges[p[x]^1].flow -= a;  
        x = edges[p[x]].from;  
    }  
    return a;  
}  
  
int Maxflow(int s, int t){  
    int flow = 0;  
    bfs(t,s);                //逆向bfs    
    //printf("ok1\n");
    memset(num,0,sizeof(num));  
    for (int i=0; i<=n; i++) num[d[i]]++;
    int x = s;  
    memset(cur,0,sizeof(cur));  
    while (d[s] < n+1){     //小于节点数目 
        if (x == t){  
            flow += Augment(s,t);  
            x = s;  
        }  
        int ok = 0;  
        for (int i=cur[x]; i<G[x].size(); i++){  
            Edge& e = edges[G[x][i]];  
            if (e.cap > e.flow && d[x] == d[e.to] + 1){  
                ok = 1;  
                p[e.to] = G[x][i];  
                cur[x] = i;  
                x = e.to;  
                break;  
            }  
        }  
        if (!ok){  
            int m = n-1;  
            for (int i=0; i<G[x].size(); i++){  
                Edge& e = edges[G[x][i]];  
                if (e.cap > e.flow) m = min(m,d[e.to]);  
            }  
            if (--num[d[x]] == 0) break;       //gap优化,能使时间复杂度降低100倍左右  
            num[d[x] = m+1]++;  
            cur[x] = 0;  
            if (x != s) x = edges[p[x]].from;  
        }  
    }  
    return flow;  
}  

int l[MAX][MAX],r[MAX][MAX],res[MAX][MAX],a[MAX],b[MAX],m;

bool judge(){
     for (int i=1; i<=n; i++)
         for (int j=1; j <= m; j++)
             if (r[i][j] < l[i][j]) return false;
     return true;
}

int main(){
	int cas;
	scanf("%d",&cas);
	while (cas--){
		init();
		scanf("%d%d",&n,&m);
		int s = n+m+1, t = n+m+2;
		int SS = 0, TT = n+m+3;
		addEdge(t,s,INF);          //注意添边t->s(原汇点到原源点),容量为无穷大 
		for (int i=1; i<=n; i++){
			scanf("%d",&a[i]);
			addEdge(SS,i,a[i]);
			addEdge(s,i,0);
			addEdge(s,TT,a[i]);
		}
		for (int i=1; i <= m; i++){
			scanf("%d",&b[i]);
			addEdge(SS,t,b[i]);
			addEdge(i+n,t,0);
			addEdge(i+n,TT,b[i]);
		}
		int x,y,z;
		char st[5];
		for (int i=1; i<=n; i++)
			for (int j = 1; j<=m; j++){
				l[i][j] = 0;
				r[i][j] = min(a[i],b[j]); 
			}
		int cc;
		scanf("%d",&cc);
		while (cc--){
			scanf("%d%d%s%d",&x,&y,st,&z);
			if (st[0] == '>'){
				if (x == 0 && y == 0){
					for (int i = 1; i <= n; i++)
						for (int j=1; j <= m; j++){
							l[i][j] = max(l[i][j],z+1);
						}
				}
				else if (x == 0){
					for (int i=1; i<=n; i++){
						l[i][y] = max(l[i][y],z+1);
					}
				}
				else if (y == 0){
					for (int i=1; i<=m; i++){
						l[x][i] = max(l[x][i],z+1);
					}
				}
				else{
					l[x][y] = max(l[x][y],z+1);
				}
			}
			else if (st[0] == '<'){
				if (x == 0 && y == 0){
					for (int i=1; i<=n; i++)
						for (int j = 1; j<=m; j++){
							r[i][j] = min(r[i][j],z-1);
						}
				}
				else if (x == 0){
					for (int i = 1; i<=n; i++){
						r[i][y] = min(r[i][y],z-1);
					}
				}
				else if (y == 0){
					for (int i = 1; i<=m; i++){
						r[x][i] = min(r[x][i],z-1);
					}
				}
				else {
					r[x][y] = min(r[x][y],z-1);
				}
			}
			else{
				if (x == 0 && y == 0){
					for (int i=1; i<=n; i++){
						for (int j=1; j<=m; j++){
                            l[i][j] = max(l[i][j],z);
                            r[i][j] = min(r[i][j],z);
                        }
					}
				}
				else if (x == 0){
                      for(int i = 1; i <= n; i++){
                              l[i][y] = max(l[i][y],z);
                              r[i][y] = min(r[i][y],z);
                      }
                }
                else if (y == 0){
                     for (int i = 1; i<=m; i++){
                         l[x][i] = max(l[x][i],z);
                         r[x][i] = min(r[x][i],z);
                     }
                }
                else {
                     l[x][y] = max(l[x][y],z);
                     r[x][y] = min(r[x][y],z);
                }              
			}
		}
		if (!judge()){
             printf("IMPOSSIBLE\n");
             if (cas) printf("\n");
             continue;
        }
		for (int i=1; i <= n; i++)
		    for (int j = 1; j <= m; j++){
                addEdge(SS,j+n,l[i][j]);
                addEdge(i,j+n,r[i][j] - l[i][j]);
                addEdge(i,TT,l[i][j]);
            }
        int nt = n;
        n = TT;
        Maxflow(SS,TT);
        int ok = 1;
        for (int i = 0; i<edges.size(); i++){
            Edge e = edges[i];
            int u = e.from;
            int v = e.to;
            if ((u == SS || v == TT) && e.flow != e.cap ){
                   ok = 0;
                   break;
            }
        }
        if (!ok){
            printf("IMPOSSIBLE\n");
            if (cas) printf("\n");
            continue;
        }
        for (int i = 0; i<edges.size(); i++){
            Edge e = edges[i];
            int u = e.from;
            int v = e.to;
            res[u][v] = e.flow;
        }
        for (int i=1; i<=nt; i++){
            printf("%d",res[i][1+nt] + l[i][1]);
            for (int j = 2; j<=m; j++) printf(" %d",res[i][j+nt]+l[i][j]);
            printf("\n");
        }
        if (cas) printf("\n");
	}
	return 0;
}




































评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值