简单的一些网络流问题

该博客探讨了如何利用二分查找法解决POI2005中的Dicing问题,涉及最小割算法的运用。通过 FlowGraph 数据结构实现并解释了如何通过深度优先搜索和最大流量找到满足条件的最小割。关键步骤包括初始化图,进行广度优先遍历,以及在DFS中更新流量和判断割是否达到目标。
摘要由CSDN通过智能技术生成

POI2005, Dicing

二分答案跑出是不是满流即可

#include <bits/stdc++.h>
using namespace std;
//using ll = long long;
#define int long long
const int V = 1010;
const int E = 101000;
template<typename T>
struct FlowGraph {
	int s, t, vtot;
	int h[V], idx;
	int d[V], cur[V];
	int e[E*2];
	int ne[E*2];
	int f[E*2];
	void add(int a,int b,int c) {
		e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;
		e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++;
	}

	bool bfs() {
		for (int i = 1; i <= vtot; i++) {
			d[i] = 0;
			cur[i] = h[i];
		}
		queue<int> q;
		q.push(s);
		d[s] = 1;
		while (!q.empty()) {
			int u = q.front();
			q.pop();
			for (int i =h[u]; ~i; i = ne[i]) {
				int v=e[i];
				if (f[i] && !d[v]) {
					d[v] = d[u] + 1;
					if (v == t) return true;
					q.push(v);
				}
			}
		}
		return false;
	}
	T dfs(int u, T m) {
		if (u == t) return m;
		T flow = 0;
		for (int i = cur[u]; ~i; cur[u] = i = ne[i])
			if (f[i] && d[e[i]] == d[u] + 1) {
				T t = dfs(e[i], min(m, f[i]));
				f[i] -= t;
				f[i ^ 1] += t;
				m -= t;
				flow += t;
				if (!m) break;
			}
		if (!flow) d[u] = -1;
		return flow;
	}
	T dinic() {
		T flow=0;
		while (bfs()) flow += dfs(s, numeric_limits<T>::max());
		return flow;
	}
	void init(int s_, int t_, int vtot_) {
		s = s_;
		t = t_;
		vtot = vtot_;
		idx = 0;
		for (int i = 1; i <= vtot; i++) h[i] = -1;
	}
};

FlowGraph<int> g;
int n, m, s, t;
pair<int,int>q[10010];
bool check(int x) {
	s=n+m+1;
	t=n+m+2;
	g.init(s,t,t);
	for(int i=1; i<=m; i++) {
		g.add(s,i,1);
		g.add(i,m+q[i].first,1);
		g.add(i,m+q[i].second,1);
	}
	for(int i=1; i<=n; i++) {
		g.add(i+m,t,x);
	}
	return g.dinic()==m;
}
signed main() {
	cin>>n>>m;
	for(int i=1; i<=m; i++) {
		cin>>q[i].first>>q[i].second;
	}
	int l=0,r=m;
	while(l<=r) {
		int mid=(l+r)>>1;
		if(check(mid))r=mid-1;
		else l=mid+1;
	}
	cout<<r+1<<endl;

}

bzoj 最小生成树(最小割模板)

#include <bits/stdc++.h>
using namespace std;
//using ll = long long;
#define int long long
const int V = 20010;
const int E = 201000;
template<typename T>
struct FlowGraph {
	int s, t, vtot;
	int h[V], idx;
	int d[V], cur[V];
	int e[E*2];
	int ne[E*2];
	int f[E*2];
	/*struct edge {
		int v, nxt;
		T f;
	} e[E * 2];
	void addedge(int u,int v, T f){
		e[etot]= {v, head[u], f}; head[u] = etot++;
		e[etot]= {u, head[v], 0}; head[v] = etot++;
	}*/
	void add(int a,int b,int c,int d) {
		e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;
		e[idx]=a,f[idx]=d,ne[idx]=h[b],h[b]=idx++;
	}

	bool bfs() {
		for (int i = 1; i <= vtot; i++) {
			d[i] = 0;
			cur[i] = h[i];
		}
		queue<int> q;
		q.push(s);
		d[s] = 1;
		while (!q.empty()) {
			int u = q.front();
			q.pop();
			for (int i =h[u]; ~i; i = ne[i]) {
				int v=e[i];
				if (f[i] && !d[v]) {
					d[v] = d[u] + 1;
					if (v == t) return true;
					q.push(v);
				}
			}
		}
		return false;
	}

	/*	T dfs(int u, T m) {
			if (u == t) return m;
			T flow = 0;
			for (int i = cur[u]; ~i; cur[u] = i = ne[i]){
				int v=e[i];
				if (f[i] && d[v] == d[u] + 1) {
					T t = dfs(v, min(m-flow, f[i]));
					if(!t)d[v]=-1;
					f[i] -= t;
					f[i ^ 1] += t;
					flow+=t;
				}
			}
			return flow;
	    }*/

	T dfs(int u, T m) {
		if (u == t) return m;
		T flow = 0;
		for (int i = cur[u]; ~i; cur[u] = i = ne[i])
			if (f[i] && d[e[i]] == d[u] + 1) {
				T t = dfs(e[i], min(m, f[i]));
				f[i] -= t;
				f[i ^ 1] += t;
				m -= t;
				flow += t;
				if (!m) break;
			}
		if (!flow) d[u] = -1;
		return flow;
	}
	T dinic() {
		T flow=0;
		while (bfs()) flow += dfs(s, numeric_limits<T>::max());
		return flow;
	}
	void init(int s_, int t_, int vtot_) {
		s = s_;
		t = t_;
		vtot = vtot_;
		idx = 0;
		for (int i = 1; i <= vtot; i++) h[i] = -1;
	}
};

FlowGraph<int> g;
int n, m, s, t, k;
array<int, 3> e[E];
signed main() {
	cin>>n>>m;
	for(int i=1; i<=m; i++) {
		int a,b,c;
		cin>>a>>b>>c;
		e[i]= {a,b,c};
	}
	cin>>s>>t>>k;
	g.init(s,t,n);
	for(int i=1; i<=m; i++) {
		if(e[i][2]<k)g.add(e[i][0],e[i][1],1,1);
	}
	int ans1=g.dinic();
	g.init(s, t, n);
	for(int i=1; i<=m; i++) {
		if(e[i][2]>k)g.add(e[i][0],e[i][1],1,1);
	}
	cout<<ans1+g.dinic()<<endl;
}

link

拆点求最小割

//#include <bits/stdc++.h>
#include <iostream>
#include <cstring>
#include <queue>
#include <cmath>
#include <limits>
using namespace std;
//using ll = long long;
#define int long long
const int V = 1010;
const int E = 101000;
template<typename T>
struct FlowGraph {
	int s, t, vtot;
	int h[V], idx;
	int d[V], cur[V];
	int e[E*2];
	int ne[E*2];
	int f[E*2];
	/*struct edge {
		int v, nxt;
		T f;
	} e[E * 2];
	void addedge(int u,int v, T f){
		e[etot]= {v, head[u], f}; head[u] = etot++;
		e[etot]= {u, head[v], 0}; head[v] = etot++;
	}*/
	void add(int a,int b,int c) {
		e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;
		e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++;
	}

	bool bfs() {
		for (int i = 1; i <= vtot; i++) {
			d[i] = 0;
			cur[i] = h[i];
		}
		queue<int> q;
		q.push(s);
		d[s] = 1;
		while (!q.empty()) {
			int u = q.front();
			q.pop();
			for (int i =h[u]; ~i; i = ne[i]) {
				int v=e[i];
				if (f[i] && !d[v]) {
					d[v] = d[u] + 1;
					if (v == t) return true;
					q.push(v);
				}
			}
		}
		return false;
	}

	/*	T dfs(int u, T m) {
			if (u == t) return m;
			T flow = 0;
			for (int i = cur[u]; ~i; cur[u] = i = ne[i]){
				int v=e[i];
				if (f[i] && d[v] == d[u] + 1) {
					T t = dfs(v, min(m-flow, f[i]));
					if(!t)d[v]=-1;
					f[i] -= t;
					f[i ^ 1] += t;
					flow+=t;
				}
			}
			return flow;
	    }*/

	T dfs(int u, T m) {
		if (u == t) return m;
		T flow = 0;
		for (int i = cur[u]; ~i; cur[u] = i = ne[i])
			if (f[i] && d[e[i]] == d[u] + 1) {
				T t = dfs(e[i], min(m, f[i]));
				f[i] -= t;
				f[i ^ 1] += t;
				m -= t;
				flow += t;
				if (!m) break;
			}
		if (!flow) d[u] = -1;
		return flow;
	}
	T dinic() {
		T flow=0;
		while (bfs()) flow += dfs(s, numeric_limits<T>::max());
		return flow;
	}
	void init(int s_, int t_, int vtot_) {
		s = s_;
		t = t_;
		vtot = vtot_;
		idx = 0;
		for (int i = 1; i <= vtot; i++) h[i] = -1;
	}
	int st[V];
//	memset(st,0,sizeof(st));
	void dfs(int u) {
		st[u]=1;
		for(int i=h[u]; ~i; i=ne[i]) {
			if(f[i]&&!st[e[i]])
			dfs(e[i]);
		}
	}
};
int inf =(int)1<<60;
FlowGraph<int> g;
int n, m;
signed main() {
	cin>>n>>m;
	g.init(2,2*n-1,2*n);
	for(int i=1; i<=m; i++) {
		int a,b;
		cin>>a>>b;
		g.add(2*a,2*b-1,inf);
		g.add(2*b,2*a-1,inf);
	}
	for(int i=1; i<=n; i++) {
		int x;
		cin>>x;
		g.add(2*i-1,2*i,x);
	}
	cout<<g.dinic()<<endl;
	g.dfs(2);
	vector<int>ans;
	for(int i=2; i<n; i++) {
		if(g.st[2*i-1]&&!g.st[2*i]) {
			ans.push_back(i);
		}
	}
/*	for(int i=1;i<n;i++){
		cout<<g.st[2*i-1]<<" "<<g.st[2*i]<<endl;
	}*/
	cout<<ans.size()<<endl;
	for(auto x:ans)cout<<x<<" ";
	cout<<endl;
}

link


#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const int V = 20100;
const int E = 201000;

template<typename T>
struct MinCostGraph {
	int s, t, vtot;
	int h[V], idx;
	T d[V], flow, cost;
	int pre[V];
	bool vis[V];
	int f[E*2];
	int w[E*2];
	int e[E*2];
	int ne[E*2];
	/*	struct edge {
			int v, nxt;
			T f, c;
		} e[E * 2];
		/*void addedge(int u,int v, T f, T c, T f2 = 0) {
			e[etot]= {v, head[u], f, c};
			head[u] = etot++;
			e[etot]= {u, head[v], f2, -c};
			head[v] = etot++;
		}*/
	void add(int a, int b, int c, int d) {
		e[idx] = b, f[idx] = c, w[idx] = d, ne[idx] = h[a], h[a] = idx ++ ;
		e[idx] = a, f[idx] = 0, w[idx] = -d, ne[idx] = h[b], h[b] = idx ++ ;
	}

	bool spfa() {
		T inf = numeric_limits<T>::max() / 2;
		for (int i = 1; i <= vtot; i++) {
			d[i] = inf;
			vis[i] = false;
			pre[i] = -1;
		}
		d[s] = 0;
		vis[s] = true;
		queue<int> q;
		q.push(s);
		while (!q.empty()) {
			int u = q.front();
			q.pop();
			vis[u] = false;
			for(int i=h[u]; ~i; i=ne[i]) {
				int v = e[i];
				if (f[i] && d[v] > d[u] + w[i]) {
					d[v] = d[u] + w[i];
					pre[v] = i;
					if (!vis[v]) {
						vis[v] = 1;
						q.push(v);
					}
				}
			}
		}
		return d[t] != inf;
	}

	void augment() {
		int u = t;
		T q = numeric_limits<T>::max();
		while (~pre[u]) {
			q = min(q, f[pre[u]]);
			u = e[pre[u] ^ 1];
		}
		flow += q;
		cost += q * d[t];
		u = t;
		while (~pre[u]) {
			f[pre[u]] -= q;
			f[pre[u] ^ 1] += q;
			u = e[pre[u] ^ 1];
		}
	}

	pair<T, T> solve() {
		flow = 0;
		cost = 0;
		while (spfa()) augment();
		return {flow, cost};
	}
	void init(int s_, int t_, int vtot_) {
		s = s_;
		t = t_;
		vtot = vtot_;
		idx = 0;
		for (int i = 1; i <= vtot; i++) h[i] = -1;
	}
};

MinCostGraph<int> g1,g2;
int n, m;
int main() {
	cin>>n>>m;
	g1.init(n+m+1,n+m+2,n+m+2);
	g2.init(n+m+1,n+m+2,n+m+2);
	for(int i=1; i<=n; i++) {
		int x;
		cin>>x;
		g1.add(n+m+1,i,x,0);
		g2.add(n+m+1,i,x,0);
	}
	for(int i=1; i<=m; i++) {
		int x;
		cin>>x;
		g1.add(i+n,n+m+2,x,0);
		g2.add(i+n,n+m+2,x,0);
	}
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=m; j++) {
			int x;
			cin>>x;
			g1.add(i,j+n,1<<30,x);
			g2.add(i,j+n,1<<30,-x);
		}
	}
	pair<int,int>t1=g1.solve();
	pair<int,int>t2=g2.solve();
	cout<<t1.second<<endl;
	cout<<t2.second*(-1)<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值