网络流进阶

先把三道例题扔在这里吧qvq
无源汇有上下界可行流
有源汇有上下界最大流
有源汇有上下界最小流

无源汇有上下界可行流

首先默认把下界跑满 但显然这样是不满足流量平衡的
所以建立超级源S,超级汇T
把所有“入不敷出”的点向T连一条大小为 出流-入流 的边
把S向所有入流大的点连一条大小为 入流-出流 的边
此时跑一遍网络流 如果与S相连的边都满流了 那么T也满流了
整个图即可行 否则不可行

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
const int N = 205;
const int M = 1e6;
const int inf = 0x3f3f3f3f;
struct Edge{
	int v, f, next;
}edge[M];
int head[N], cur[N], esize = -1;
inline void addedge(int x, int y, int z){
	//printf("%d %d %d\n", x, y, z);
	edge[++esize] = (Edge){y, z, head[x]};
    head[x] = esize;
	edge[++esize] = (Edge){x, 0, head[y]};
    head[y] = esize;
}

int n, m, S, T, cnt, mf;
int low[M], upp[M], in[N], out[N];
int dis[N], fro;
queue<int> que;
bool bfs(){
	memset(dis, 0, sizeof(dis));
	que.push(S); dis[S] = 1;
	while(!que.empty()){
		fro = que.front(); que.pop();
		for(int i = head[fro], vv; ~i; i = edge[i].next){
			vv = edge[i].v;
			if(!dis[vv] && edge[i].f > 0){
				que.push(vv);
				dis[vv] = dis[fro] + 1;
			}
		}
	}
	return dis[T];
}
int dfs(int x, int rest){
	if(!rest || x == T) return rest;
	for(int& i = cur[x], vv; ~i; i = edge[i].next){
		vv = edge[i].v;
		if(dis[vv] == dis[x] + 1 && edge[i].f > 0){
			int d = dfs(vv, min(rest, edge[i].f));
			if(d > 0){
				edge[i].f -= d;
				edge[i ^ 1].f += d;
				return d; 
			}
		}
	}
	return 0;
}

void dinic(){
	mf = 0;
	while(bfs()){
		//for(int i = 1; i <= T; ++i) printf("%d %d\n", i, dis[i]); 
		for(int i = 1; i <= T; ++i) cur[i] = head[i];
		mf += dfs(S, inf);
	    //printf("mf = %d\n", mf);
	}
} 

int main(){
	memset(head, -1, sizeof(head));
	scanf("%d%d", &n, &m);
	for(int i = 1, x, y; i <= m; ++i){
		scanf("%d%d%d%d", &x, &y, &low[i], &upp[i]);
	    addedge(x, y, upp[i] - low[i]);
	    out[x] += low[i];
	    in[y] += low[i];
	}
	S = n + 1, T = n + 2;
	for(int i = 1; i <= n; ++i){
		if(in[i] > out[i]){
			addedge(S, i, in[i] - out[i]);
			cnt += in[i] - out[i]; 
		}
		else if(out[i] > in[i]) addedge(i, T, out[i] - in[i]);
	}
	dinic();
	if(mf == cnt){
		printf("YES\n");
		for(int i = 1; i <= m; ++i){
			printf("%d\n", low[i] + edge[(i << 1) - 1].f);
		}
	} 
	else printf("NO\n");
    return 0;	
}

有源汇有上下界最大流

在原图上再跑一次最大流就好啦

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
const int N = 205;
const int M = 1e6;
const int inf = 0x3f3f3f3f;
struct Edge{
	int v, f, next;
}edge[M];
int head[N], cur[N], esize = -1;
inline void addedge(int x, int y, int z){
	//printf("%d %d %d\n", x, y, z);
	edge[++esize] = (Edge){y, z, head[x]};
    head[x] = esize;
	edge[++esize] = (Edge){x, 0, head[y]};
    head[y] = esize;
}

int n, m, S, T, SS, TT, cnt, mf;
int low[M], upp[M], d[N];
int dis[N], fro;
queue<int> que;
bool bfs(int s, int t){
	memset(dis, 0, sizeof(dis));
	que.push(s); dis[s] = 1;
	while(!que.empty()){
		fro = que.front(); que.pop();
		for(int i = head[fro], vv; ~i; i = edge[i].next){
			vv = edge[i].v;
			if(!dis[vv] && edge[i].f > 0){
				que.push(vv);
				dis[vv] = dis[fro] + 1;
			}
		}
	}
	//printf("%d\n", dis[T]);
	return dis[t];
}
int dfs(int x, int rest, int t){
	//	printf("%d %d\n", x, rest);
	if(!rest || x == t) return rest;
	for(int& i = cur[x], vv; ~i; i = edge[i].next){
		vv = edge[i].v;
		if(dis[vv] == dis[x] + 1 && edge[i].f > 0){
			int d = dfs(vv, min(rest, edge[i].f), t);
			if(d > 0){
				//printf("%d\n", d);
				edge[i].f -= d;
				edge[i ^ 1].f += d;
				return d; 
			}
		}
	}
	return 0;
}

void dinic(int s, int t){
	mf = 0;
	while(bfs(s, t)){
		//for(int i = 1; i <= T; ++i) printf("%d %d\n", i, dis[i]); 
		memcpy(cur, head, sizeof(cur));
		mf += dfs(s, inf, t);
	    //printf("mf = %d\n", mf);
	}
} 

int main(){
	memset(head, -1, sizeof(head));
	scanf("%d%d%d%d", &n, &m, &S, &T);
	for(int i = 1, x, y; i <= m; ++i){
		scanf("%d%d%d%d", &x, &y, &low[i], &upp[i]);
	    addedge(x, y, upp[i] - low[i]);
	    d[x] -= low[i];
	    d[y] += low[i];
	}
	//printf("*");
	SS = n + 1, TT = n + 2;
	for(int i = 1; i <= n; ++i){
		if(d[i] > 0){
			addedge(SS, i, d[i]);
			cnt += d[i]; 
		}
		else if(d[i] < 0) addedge(i, TT, -d[i]);
	}
	addedge(T, S, inf);
	int rec = esize;
	
	dinic(SS, TT);
	
	if(mf != cnt){
		printf("please go home to sleep\n");
		return 0;
	} 
	
	head[S] = edge[head[S]].next;
	head[T] = edge[head[T]].next;
    dinic(S, T); mf += edge[rec].f;
    printf("%d", mf);
	return 0;	
}

有源汇有上下界最小流

1.从SS到TT跑最大流
2.从T到S连一条大小为INF的边
3.从SS到TT跑最大流
4.最后T到S的流量就是最小流

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
const int N = 5e4 + 9;
const int M = 1e6;
const int inf = 0x3f3f3f3f;
struct Edge{
	int v, f, next;
}edge[M];
int head[N], cur[N], esize = -1;
inline void addedge(int x, int y, int z){
	//printf("%d %d %d\n", x, y, z);
	edge[++esize] = (Edge){y, z, head[x]};
    head[x] = esize;
	edge[++esize] = (Edge){x, 0, head[y]};
    head[y] = esize;
}

int n, m, S, T, SS, TT, cnt, mf;
int low[M], upp[M], d[N];
int dis[N], fro;
queue<int> que;
bool bfs(int s, int t){
	memset(dis, 0, sizeof(dis));
	que.push(s); dis[s] = 1;
	while(!que.empty()){
		fro = que.front(); que.pop();
		for(int i = head[fro], vv; ~i; i = edge[i].next){
			vv = edge[i].v;
			if(!dis[vv] && edge[i].f > 0){
				que.push(vv);
				dis[vv] = dis[fro] + 1;
			}
		}
	}
	//printf("%d\n", dis[T]);
	return dis[t];
}
int dfs(int x, int rest, int t){
	//	printf("%d %d\n", x, rest);
	if(!rest || x == t) return rest;
	int tmp = 0;
	for(int& i = cur[x], vv; ~i; i = edge[i].next){
		vv = edge[i].v;
		if(dis[vv] == dis[x] + 1 && edge[i].f > 0){
			int d = dfs(vv, min(rest - tmp, edge[i].f), t);
			edge[i].f -= d;
			edge[i ^ 1].f += d;
			tmp += d;
			if(tmp == rest) return tmp;
		}
	}
	return tmp;
}

void dinic(int s, int t){
	while(bfs(s, t)){
		//for(int i = 1; i <= T; ++i) printf("%d %d\n", i, dis[i]); 
		memcpy(cur, head, sizeof(cur));
		mf += dfs(s, inf, t);
	    //printf("mf = %d\n", mf);
	}
} 

int main(){
	memset(head, -1, sizeof(head));
	scanf("%d%d%d%d", &n, &m, &S, &T);
	for(int i = 1, x, y; i <= m; ++i){
		scanf("%d%d%d%d", &x, &y, &low[i], &upp[i]);
	    addedge(x, y, upp[i] - low[i]);
	    d[x] -= low[i];
	    d[y] += low[i];
	}
	//printf("*");
	SS = n + 1, TT = n + 2;
	for(int i = 1; i <= n; ++i){
		if(d[i] > 0){
			addedge(SS, i, d[i]);
			cnt += d[i]; 
		}
		else if(d[i] < 0) addedge(i, TT, -d[i]);
	}
	
	dinic(SS, TT);
	
	addedge(T, S, inf);
	int rec = esize;
	
    dinic(SS, TT); 
	if(mf != cnt){
		printf("please go home to sleep\n");
		return 0;
	} 
    else printf("%d", edge[rec].f);
	return 0;	
}
posted @ 2019-03-22 23:05  hjmmm  阅读(167)  评论(0编辑  收藏  举报