网络流

EK求最大流

#include <bits/stdc++.h>
using namespace std;
const int N = 2005, M = 20005;
const int INF = 0x3f3f3f3f;
struct edge
{
	int to, nxt, w;
}e[M];
int head[N], d[N], q[N], cnt = -1, pre[N], ver[N];
int n, m, S, T;
void add_edge(int u, int v, int w)
{
	e[++ cnt].to = v, e[cnt].w = w, e[cnt].nxt = head[u], head[u] = cnt;
	e[++ cnt].to = u, e[cnt].w = 0, e[cnt].nxt = head[v], head[v] = cnt;
	return ;
}
bool bfs()
{
	int tot = 0, now = 1;
	q[++ tot] = S;
	for (int i = 1; i <= n; ++ i) ver[i] = 0, d[i] = 0, pre[i] = 0;
	ver[S] = 1, d[S] = INF;//请注意q是一个队列 
	while(now <= tot)
	{
		int x = q[now ++];
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(!ver[y] && e[i].w > 0)
			{
				d[y] = min(d[x], e[i].w);
				pre[y] = i, ver[y] = 1;
				if(y == T) return true;
				q[++ tot] = y;
			} 
		}
	}
	return false;
}
int EK()
{
	int ans = 0;
	while(bfs())
	{
		ans += d[T];
		for (int i = T; i != S; i = e[pre[i] ^ 1].to)
		{
			e[pre[i]].w -= d[T];
			e[pre[i] ^ 1].w += d[T];
		}
	}
	return ans;
}
int main()
{
	memset(head, -1, sizeof(head));
	scanf("%d %d %d %d", &n, &m, &S, &T);
	while(m --)
	{
		int u, v, c;
		scanf("%d %d %d", &u, &v, &c);
		add_edge(u, v, c);
	}
	printf("%d", EK());
	return 0;
}

Dinic/ISAP求最大流

时间复杂度是\(O(n^2m)\)

#include <bits/stdc++.h>
using namespace std;
const int N = 20005, M = 200005;
const int inf = 0x3f3f3f3f;
struct edge
{
	int to, nxt, w;
}e[M];
int n, m, S, T;
int head[N], cnt = -1, d[N], cur[N], q[N];
void add_edge(int u, int v, int w)
{
	e[++ cnt].to = v, e[cnt].nxt = head[u], e[cnt].w = w, head[u] = cnt;
	e[++ cnt].to = u, e[cnt].nxt = head[v], e[cnt].w = 0, head[v] = cnt;
	return ;
}
bool bfs()
{
	int tt = 1, hh = 0;
	for (int i = 0; i <= n; ++ i) d[i] = -1;
	q[++ hh] = S, d[S] = 1, cur[S] = head[S]; 
	while(tt <= hh)
	{
		int x = q[tt ++];
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w > 0)
			{
				d[y] = d[x] + 1, cur[y] = head[y];
				if(y == T) return true;
				q[++ hh] = y;
			}
		}
	}
	return false;
}
int dfs(int now, int lim)
{
	if(now == T) return lim;
	int flow = 0; 
	for (int i = cur[now]; flow < lim && i != -1; i = e[i].nxt)
	{
		int x = e[i].to;
		cur[now] = i;
		if(d[x] == d[now] + 1 && e[i].w > 0)
		{
			int t = dfs(x, min(lim - flow, e[i].w));
			if(!t) d[x] = -1;
			e[i].w -= t, e[i ^ 1].w += t;
			flow += t;
		}
	}
	return flow;
}
int dinic()
{
	int ans = 0, flow = 0;
	while(bfs()) while(flow = dfs(S, inf)) ans += flow;
	return ans;
}
int main()
{
	scanf("%d%d%d%d", &n, &m, &S, &T);
	for (int i = 0; i <= n; ++ i) head[i] = -1;
	while(m --)
	{
		int u, v, c;
		scanf("%d %d %d", &u, &v, &c);
		add_edge(u, v, c);
	}
	printf("%d", dinic() );
}

飞行员配对方案问题

#include <bits/stdc++.h>
using namespace std;
const int N = 205, M = 6005, inf = 0x3f3f3f3f;
int m, n, S, T, cnt = -1;
struct edge
{
	int to, nxt, w;
}e[M];
int head[N], cur[N], q[N], d[N];
void add_edge(int u, int v, int w)
{
	e[++ cnt].to = v, e[cnt].nxt = head[u], e[cnt].w = w, head[u] = cnt;
	e[++ cnt].to = u, e[cnt].nxt = head[v], e[cnt].w = 0, head[v] = cnt;
	return ; 
}
bool bfs()
{
	int tt = 0, hh = 1;
	for (int i = 1; i <= n + 2; ++ i) d[i] = -1;
	q[++ tt] = S, cur[S] = head[S], d[S] = 1;
	while(tt <= hh) 
	{
		int x = q[tt ++];
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w)
			{
				d[y] = d[x] + 1;
				cur[y] = head[y];
				if(y == T) return true;
				q[++ hh] = y;
			}
		}
	}
	return false;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w > 0)
		{
			int t = dfs(y, min(e[i].w, lim - flow));
			if(t == 0) d[y] = -1;
			flow += t;
			e[i].w -= t, e[i ^ 1].w += t;
		}
	}
	return flow;
}
int dinic()
{
	int ans = 0, flow = 0;
	while(bfs()) 
	{
		while(flow = dfs(S, inf)) ans += flow;
	}
	return ans;
}
int main()
{
	scanf("%d %d", &m, &n);
	memset(head, - 1, sizeof head);
	S = n + 1, T = n + 2;
	memset(head, -1, sizeof(head));
	int u, v;
	for (int i = 1; i <= m; ++ i) add_edge(S, i, 1);
	for (int i = m + 1; i <= n; ++ i) add_edge(i, T, 1);
	while(scanf("%d %d", &u, &v) != EOF)
	{
		if(u == -1 && v == -1) break;
		add_edge(u, v, 1); 
	}
	printf("%d\n", dinic());
	for (int i = 1; i <= m; ++ i)
	{
		for (int j = head[i]; j != -1; j = e[j].nxt)
		{
			if(e[j].w == 0 && e[j].to != S) printf("%d %d\n", i, e[j].to); 
		}
	}
	
}

圆桌问题

#include <bits/stdc++.h>
using namespace std;
const int N = 505, M = 100005, inf = 0x3f3f3f3f;
int n, m, S, T, cnt = -1;
struct edge
{
	int to, nxt, w;
}e[M];
int head[N], q[N], cur[N], d[N];
void add_edge(int u, int v, int w)
{
	e[++ cnt].nxt = head[u], e[cnt].to = v, e[cnt].w = w, head[u] = cnt;
	e[++ cnt].nxt = head[v], e[cnt].to = u, e[cnt].w = 0, head[v] = cnt;
	return ;
}
bool bfs()
{
	int t = 0, h = 1;
	for (int i = 1; i <= T; ++ i) d[i] = -1;
	q[++ t] = S, d[S] = 0, cur[S] = head[S];
	while(t <= h)
	{
		int x = q[t ++];
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w)
			{
				d[y] = d[x] + 1;
				cur[y] = head[y];
				if(y == T) return true;
				q[++ h] = y;
			}
		}
	}
	return false;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w)
		{
			int t = dfs(y, min(e[i].w, lim - flow));
			if(t == 0) d[y] = -1;
			flow += t;
			e[i].w -= t, e[i ^ 1].w += t;
		}
	}
	return flow;
}
int dinic()
{
	int flow = 0, ans = 0;
	while(bfs()) while(flow = dfs(S, inf)) ans += flow;
	return ans; 
}
int main()
{
	scanf("%d %d", &m, &n);
	S = n + m + 1, T = n + m + 2;
	int sum = 0;
	memset(head, -1, sizeof head);
	for (int i = 1; i <= m; ++ i)
	{
		int r; 
		scanf("%d", &r);
		add_edge(S, i, r);
		sum += r;
	}
	for (int i = m + 1; i <= n + m; ++ i)
	{
		int c;
		scanf("%d", &c);
		add_edge(i, T, c);
	}
	for (int i = 1; i <= m; ++ i)
	{
		for (int j = m + 1; j <= n + m; ++ j)
		{
			add_edge(i, j, 1);
		}
	}
//	printf("%d\n", len);
	if(dinic() == sum)
	{
		printf("1\n");
		for (int i = 1; i <= m; ++ i)
		{
			for (int j = head[i]; j != -1; j = e[j].nxt)
			{
				if(e[j].to != S && e[j].w == 0) printf("%d ", e[j].to - m);
			}
			printf("\n");
		}
	}
	else printf("0");
}

无源汇上下界可行流

/*
流入量 > 流出量 S - > u = 流入量 - 流出量
流入量 < 流出量 u - > T = 流出量 - 流入量 
*/
#include <bits/stdc++.h>
using namespace std;
const int M = 30005, N = 405, inf = 0x3f3f3f3f;
int n, m, cnt = -1;
int head[N], cur[N], S, T, to[N], from[N], q[N], ed[M], lower[M];
int d[N];
struct edge
{
	int to, w, nxt;
}e[M];
void add_edge(int u, int v, int w)
{
	e[++ cnt].to = v, e[cnt].nxt = head[u], e[cnt].w = w, head[u] = cnt;
	e[++ cnt].to = u, e[cnt].nxt = head[v], e[cnt].w = 0, head[v] = cnt;
	return ;
}
bool bfs()
{
	int tt = 0, hh = 1;
	q[++ tt] = S;
	for (int i = 1; i <= T; ++ i) d[i] = -1;
	d[S] = 1, cur[S] = head[S];
	while(tt <= hh)
	{
		int x = q[tt ++];
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w)
			{
				d[y] = d[x] + 1;
				cur[y] = head[y];
				if(y == T) return true;
				q[++ hh] = y;
			}
		}
	}
//	printf("QQQ\n");
	return false;
	
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w)
		{
			int t = dfs(y, min(e[i].w, lim - flow));
			if(t == 0) d[y] = -1;
			flow += t;
			e[i].w -= t, e[i ^ 1].w += t;
		}
	}
	return flow;
}
int main()
{
	scanf("%d %d", &n, &m);
	memset(head, -1, sizeof(head));
	for (int i = 1; i <= m; ++ i)
	{
		int a, b, c, d;
		scanf("%d %d %d %d", &a, &b, &c, &d);
		to[b] += c, from[a] += c;
		add_edge(a, b, d - c);
		ed[i] = cnt, lower[i] = c;
	}	
	S = n + 1, T = n + 2;
	for (int i = 1; i <= n; ++ i)
	{
		if(to[i] > from[i]) add_edge(S, i, to[i] - from[i]);
		else if(to[i] < from[i]) add_edge(i, T, from[i] - to[i]);
	}
//	printf("QQQ\n");
	while(bfs()) while(dfs(S, inf)) {}
	bool pd = true;
	for (int i = head[S]; i != -1; i = e[i].nxt)
	{
		if(e[i].w != 0) {pd = false; break; }
	}
	for (int i = head[T]; i != -1; i = e[i].nxt)
	{
		if(!pd) break;
		if(e[i ^ 1].w != 0) pd = false;
	}
	if(!pd) printf("NO");
	else
	{
		printf("YES\n");
		for (int i = 1; i <= m; ++ i) printf("%d\n", e[ed[i]].w + lower[i]);
	}
}

有源汇上下界最大流

#include <bits/stdc++.h>
using namespace std;
const int N = 405, M = 30005, inf = 0x3f3f3f3f;
int n, m, S, T, s, t, to[N], from[N];
int head[N], cur[N], q[N], d[N];
int cnt = -1;
struct edge
{
	int to, w, nxt;
}e[M];
void add_edge(int u, int v, int w)
{
	e[++ cnt].nxt = head[u], e[cnt].w = w, e[cnt].to = v, head[u] = cnt;
	e[++ cnt].nxt = head[v], e[cnt].w = 0, e[cnt].to = u, head[v] = cnt;
	return ;
}
bool bfs()
{
	int tt = 0, hh = 1;
	for (int i = 1; i <= T; ++ i) d[i] = -1;
	d[S] = 0, q[++ tt] = S, cur[S] = head[S];
	while(tt <= hh)
	{
		int x = q[tt ++];
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w)
			{
				d[y] = d[x] + 1;
				cur[y] = head[y];
				if(y == T) return true;
				q[++ hh] = y;
			}
		}
	}
	return false;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; flow < lim && i != -1; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w)
		{
			int val = dfs(y, min(lim - flow, e[i].w));
			if(val == 0) d[y] = -1;
			e[i].w -= val, e[i ^ 1].w += val;
			flow += val;
		}
	}
	return flow;
}
int dinic()
{
	int flow = 0, sum = 0;
	while(bfs()) 
	{
		while(flow = dfs(S, inf)) sum += flow;
	} 
//	printf("QQQ\n");
	return sum;
}
int main()
{
	scanf("%d %d %d %d", &n, &m, &s, &t);
	memset(head, -1, sizeof head);
	S = n + 1, T = n + 2;
	while(m --)
	{
		int u, v, c, d;
		scanf("%d %d %d %d", &u, &v, &c, &d);
		add_edge(u, v, d - c);
		to[v] += c, from[u] += c;
	}
	int num = 0;
	for (int i = 1; i <= n; ++ i)
	{
		if(to[i] > from[i]) add_edge(S, i, to[i] - from[i]), num += to[i] - from[i];
		else if(to[i] < from[i]) add_edge(i, T, from[i] - to[i]);
	}
	add_edge(t, s, inf);
	int flow = dinic();
	if(flow != num)
	{
		printf("No Solution");
	}
	else
	{
 		flow = e[cnt].w;
		S = s, T = t;
 		e[cnt].w = 0, e[cnt - 1].w = 0;
		flow += dinic();
		printf("%d\n", flow);
	}
	return 0;	
}

有源汇上下界最小流

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005, M = 600005;
const ll inf = 1e18;

int n, m, S, T, s, t;
ll A[N];
int head[N], cur[N], q[N], d[N];
int cnt = -1;
struct edge
{
	int to, nxt;
	ll w;
}e[M];
void add_edge(int u, int v, ll w)
{
	e[++ cnt].nxt = head[u], e[cnt].w = w, e[cnt].to = v, head[u] = cnt;
	e[++ cnt].nxt = head[v], e[cnt].w = 0, e[cnt].to = u, head[v] = cnt;
	return ;
}
bool bfs()
{
	int tt = 0, hh = 1;
	for (int i = 1; i <= T; ++ i) d[i] = -1;
	d[S] = 0, q[++ tt] = S, cur[S] = head[S];
	while(tt <= hh)
	{
		int x = q[tt ++];
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w)
			{
				d[y] = d[x] + 1;
				cur[y] = head[y];
				if(y == T) return true;
				q[++ hh] = y;
			}
		}
	}
	return false;
}
ll dfs(int x, ll lim)
{
	if(x == T) return lim;
	ll flow = 0;
	for (int i = cur[x]; flow < lim && i != -1; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w)
		{
			ll val = dfs(y, min(lim - flow, e[i].w));
			if(val == 0) d[y] = -1;
			e[i].w -= val, e[i ^ 1].w += val;
			flow += val;
		}
	}
	return flow;
}
ll dinic()
{
	ll flow = 0, sum = 0;
	while(bfs()) 
	{
		while(flow = dfs(S, inf)) sum += flow;
	} 
	return sum;
}
int main()
{
	scanf("%d %d %d %d", &n, &m, &s, &t);
	memset(head, -1, sizeof head);
	S = n + 1, T = n + 2;
	while(m --)
	{
		int u, v;
		ll c, d;
		scanf("%d %d %lld %lld", &u, &v, &c, &d);
		add_edge(u, v, d - c);
		A[u] -= c, A[v] += c;
	}
	ll num = 0;
	for (int i = 1; i <= n; ++ i)
	{
		if(A[i] > 0) add_edge(S, i, A[i]), num += A[i];
		else if(A[i] < 0) add_edge(i, T, - A[i]);
	}
	add_edge(t, s, inf);
	ll flow = dinic();
	if(flow != num)
	{
		printf("No Solution");
	}
	else
	{
 		flow = e[cnt].w;
		S = t, T = s;
 		e[cnt].w = 0, e[cnt - 1].w = 0;
		flow -= dinic();
		printf("%lld\n", flow);
	}
	return 0;	
}

多源汇最大流

#include <bits/stdc++.h>
using namespace std;
const int N = 10005, M = (N + N + 100005) * 2, inf = 0x3f3f3f3f;
int n, m, sc, tc, S, T, cnt = -1;
int head[N], q[N], cur[N], d[N];
struct edge
{
	int to, nxt, w;
}e[M];
void add_edge(int u, int v, int w)
{
	e[++ cnt].nxt = head[u], e[cnt].to = v, e[cnt].w = w, head[u] = cnt;
	e[++ cnt].nxt = head[v], e[cnt].to = u, e[cnt].w = 0, head[v] = cnt;
	return ;
}
bool bfs()
{
	int tt = 0, hh = 1;
	for (int i = 1; i <= T; ++ i) d[i] = -1;
	q[++ tt] = S, cur[S] = head[S], d[S] = 1;
	while(tt <= hh)
	{
		int x = q[tt ++];
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w)
			{
				d[y] = d[x] + 1;
				if(y == T) return true;
				cur[y] = head[y];
				q[++ hh] = y;
			}
		}	
	}
	return false;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w)
		{
			int tt = dfs(y, min(lim - flow, e[i].w));
			if(tt == 0) d[y] = -1;
			flow += tt;
			e[i ^ 1].w += tt, e[i].w -= tt;
		}
	}
	return flow;
}
int dinic()
{
	int flow = 0, sum = 0;
	while(bfs()) while(flow = dfs(S, inf)) sum += flow;
	return sum;
}
int main()
{
	scanf("%d %d %d %d", &n, &m, &sc, &tc);
	memset(head, - 1, sizeof head);
	S = n + 1, T = n + 2;
	while(sc --)
	{
		int s;
		scanf("%d", &s);
		add_edge(S, s, inf);
	}
	while(tc --)
	{
		int t;
		scanf("%d", &t);
		add_edge(t, T, inf);
	}
	while(m --)
	{
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		add_edge(u, v, w);
	}
	printf("%d", dinic());
	return 0;
}

伊基的故事 I - 道路重建

#include <bits/stdc++.h>
using namespace std;
const int N = 1005, M = 5005 * 2, inf = 0x3f3f3f3f;
int n, m, head[N], S, T, cnt = -1;
int q[N], cur[N], d[N];
struct edge
{
	int to, nxt, w;
}e[M];
void add_edge(int u, int v, int w)
{
	e[++ cnt].nxt = head[u], e[cnt].to = v, e[cnt].w = w, head[u] = cnt;
	e[++ cnt].nxt = head[v], e[cnt].to = u, e[cnt].w = 0, head[v] = cnt;
	return ;
}
int vis1[N], vis2[N];
bool bfs()
{
	int tt = 0, hh = 1;
	for (int i = 0; i <= n; ++ i) d[i] = -1;
	cur[S] = head[S], d[S] = 1, q[++ tt] = S;
	while(tt <= hh)
	{
		int x = q[tt ++];
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w)
			{
				d[y] = d[x] + 1;
				if(y == T) return true;
				cur[y] = head[y];
				q[++ hh] = y; 
			}
		}
	}
	return false;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w)
		{
			int tt = dfs(y, min(e[i].w, lim - flow));
			if(tt == 0) d[y] = -1;
			flow += tt;
			e[i].w -= tt, e[i ^ 1].w += tt;
		}
	}
	return flow;
}
void dinic()
{
	while(bfs()) while(dfs(S, inf)) {}
	return ;
}
void dfs1(int x)
{
	vis1[x] = 1;
	for (int i = head[x]; i != -1; i = e[i].nxt)
	{
		int y = e[i].to;
		if(!vis1[y] && e[i].w > 0) dfs1(y);
	}
	return ;
}
void dfs2(int x)
{
	vis2[x] = 1;	
	for (int i = head[x]; i != -1; i = e[i].nxt)
	{
		int y = e[i].to;
		if(!vis2[y] && e[i ^ 1].w > 0) dfs2(y);
	}
	return ;
}
int main()
{
	scanf("%d %d", &n, &m);
	memset(head, -1, sizeof head);
	S = 0, T = n - 1;
	while(m --)
	{
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		add_edge(u, v, w);
	}
	dinic();
	dfs1(S);
	dfs2(T);
	int sum = 0;
	for (int i = 0; i < cnt; i += 2)
	{
		if(e[i].w == 0 && vis1[e[i ^ 1].to] && vis2[e[i].to]) sum ++;
	}
	printf("%d", sum);
	return 0;
}

秘密挤奶机

#include <bits/stdc++.h>
using namespace std;
const int N = 205, M = 160005, inf = 0x3f3f3f3f;

struct edge1
{
	int nxt, to, w;
}e[M];
struct edge2
{
	int u, v, w;
}g[M];
int head[N], d[N], q[N], cur[N];
int n, m, cnt = -1, p, S, T;
void add_edge(int u, int v, int w)
{
	e[++ cnt].nxt = head[u], e[cnt].to = v, e[cnt].w = w, head[u] = cnt;
	e[++ cnt].nxt = head[v], e[cnt].to = u, e[cnt].w = 0, head[v] = cnt;
	return ;
}
bool bfs()
{
	int tt = 0, hh = 1; 
	for (int i = 0; i <= T; ++ i) d[i] = -1;
	q[++ tt] = S, cur[S] = head[S], d[S] = 1;
	while(tt <= hh)
	{
		int x = q[tt ++];
		for (int i = head[x]; i != - 1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w)
			{
				d[y] = d[x] + 1;
				if(y == T) return true;
				cur[y] = head[y];
				q[++ hh] = y;
			}
		}
	}
	return false;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w)
		{
			int tt = dfs(y, min(lim - flow, e[i].w));
			if(tt == 0) d[y] = -1;
			e[i].w -= tt, e[i ^ 1].w += tt;
			flow += tt;
		}
	}
	return flow;
}
int dinic()
{
	int sum = 0, flow = 0;
	while(bfs()) while(flow = dfs(S, inf)) sum += flow;
	return sum;
}
int main()
{
	scanf("%d %d %d", &n, &m, &p);
	S = 1, T = n;
	for (int i = 1; i <= m; ++ i) scanf("%d %d %d", &g[i].u, &g[i].v, &g[i].w);
	int l = 0, r = 1000000, mid = 0, ans = 0;
	while(l <= r)
	{
		mid = (l + r) >> 1;
		for (int i = 0; i <= T; ++ i) head[i] = -1;
		cnt = -1;
		for (int i = 1; i <= m; ++ i)
		{
			if(g[i].w <= mid) add_edge(g[i].u, g[i].v, 1), add_edge(g[i].v, g[i].u, 1);
		}
		if(dinic() >= p) ans = mid, r = mid - 1;
		else l = mid + 1;
	}
	printf("%d", ans);
	return 0;
}

星际转移问题

#include <bits/stdc++.h>
using namespace std;
const int D = 50 * 30 + 5, inf = 0x3f3f3f3f;
const int N = D * 15 + 2, M = (D + 1 + 30 * D) * 2;
int S, T, tot = 0;
struct edge
{
	int nxt, to, w;
}e[M];
int head[N], d[N], q[N], cur[N], cnt = -1;
void add_edge(int u, int v, int w)
{
	e[++ cnt].nxt = head[u], e[cnt].to = v, e[cnt].w = w, head[u] = cnt;
	e[++ cnt].nxt = head[v], e[cnt].to = u, e[cnt].w = 0, head[v] = cnt;
	return ;
}
int n, m, k;
int h[25], r[25], s[25][20];

int fa[N];
int findset(int x)
{
	if(x == fa[x]) return x;
	else return fa[x] = findset(fa[x]);
}
void unionset(int x, int y)
{
	x = findset(x), y = findset(y);
	if(x == y) return ;
	fa[x] = y;
	return ;
}
int calc(int day, int num)
{
	if(num == -1) num = n + 3;
	else num = num + 2;
	return (n + 2) * day + num;
}
bool bfs()
{
	int tt = 0, hh = 1;
	for (int i = 0; i <= tot; ++ i) d[i] = -1;
	q[++ tt] = S, cur[S] = head[S], d[S] = 1;
	while(tt <= hh)
	{
		int x = q[tt ++];
		for (int i = head[x]; i != - 1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w)
			{
				d[y] = d[x] + 1;
				if(y == T) return true;
				cur[y] = head[y];
				q[++ hh] = y;
			}
		}
	}
	return false;
} 
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w)
		{
			int tt = dfs(y, min(lim - flow, e[i].w));
			if(tt == 0) d[y] = -1;
			e[i].w -= tt, e[i ^ 1].w += tt;
			flow += tt;
		}
	}
	return flow;
}
int dinic()
{
	int flow = 0, sum = 0;
	while(bfs()) while(flow = dfs(S, inf)) sum += flow;
	return sum;
}
int main()
{
	scanf("%d %d %d", &n, &m, &k);
	memset(head, -1, sizeof(head));
	for (int i = 0; i <= n + 1; ++ i) fa[i] = i;
	for (int i = 1; i <= m; ++ i)
	{
		scanf("%d %d", &h[i], &r[i]);
		for (int j = 1; j <= r[i]; ++ j) 
		{
			scanf("%d", &s[i][j]);
			if(j >= 2)
			{
				int x = s[i][j], y = s[i][j - 1];
				if(x == -1) x = n + 1;
				if(y == -1) y = n + 1;
				unionset(x, y);
			}
		}
	}
	if(findset(0) != findset(n + 1))
	{
		printf("0");
		return 0;
	}
	S = 0, T = 1;
	add_edge(S, calc(0, 0), k);
	add_edge(calc(0, -1), T, inf);
	int day = 0, sum = 0;
	while(true)
	{
		day ++;
		tot = calc(day, -1);
		for (int i = 1; i <= m; ++ i)
		{
			int start = s[i][day % r[i] == 0 ? r[i] : day % r[i]];
			int end = s[i][day % r[i] == 0 ? 1 : day % r[i] + 1];
			add_edge(calc(day - 1, start), calc(day, end), h[i]);
		}
		for (int i = 0; i <= n; ++ i)
		{
			add_edge(calc(day - 1, i), calc(day, i), inf);
		}
		add_edge(calc(day, -1), T, inf);
		sum += dinic();
		if(sum == k) 
		{
			printf("%d\n", day);
			break;
		}
	}
	return 0;
	
}

餐饮

#include <bits/stdc++.h>
using namespace std;
const int N = 405, M = (100 * 100 * 100 + 305) * 2;
int head[N], q[N], d[N], cur[N], S, T;
const int inf = 0x3f3f3f3f;
int cnt = -1, n, F, D;
struct edge
{
	int nxt, to, w;
}e[M];
int calc(int opt, int x)
{
	if(opt == 1) return x;
	if(opt == 2) return x + F;
	if(opt == 3) return x + F + n;
	if(opt == 4) return x + F + n + n;
}
void add_edge(int u, int v, int w)
{
	e[++ cnt].nxt = head[u], e[cnt].to = v, e[cnt].w = w, head[u] = cnt;
	e[++ cnt].nxt = head[v], e[cnt].to = u, e[cnt].w = 0, head[v] = cnt;
	return ;
}
bool bfs()
{
	int tt = 0, hh = 1;
	q[++ tt] = S;
	for (int i = 0; i <= T; ++ i) d[i] = -1;
	cur[S] = head[S], d[S] = 1;
	while(tt <= hh)
	{
		int x = q[tt ++];
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w)
			{
				d[y] = d[x] + 1;
				if(y == T) return true;
				cur[y] = head[y];
				q[++ hh] = y;
			}
		}
	}
	return false;	
} 
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w)
		{
			int tt = dfs(y, min(lim - flow, e[i].w));
			if(tt == 0) d[y] = -1;
			e[i].w -= tt, e[i ^ 1].w += tt;
			flow += tt;
		}
	}
	return flow;
}
int dinic()
{
	int flow = 0, sum = 0;
	while(bfs()) while(flow = dfs(S, inf)) sum += flow;
	return sum;
}
int main()
{
	memset(head, - 1, sizeof head);
	scanf("%d %d %d", &n, &F, &D);
	S = 0, T = F + n + n + D + 1;
	for (int i = 1; i <= F; ++ i) add_edge(S, calc(1, i), 1);
	for (int i = 1; i <= n; ++ i)
	{
		int f, d, x;
		scanf("%d %d", &f, &d);
		for (int j = 1; j <= f; ++ j) 
		{
			scanf("%d", &x);
			add_edge(calc(1, x), calc(2, i), 1);
		}
		for (int j = 1; j <= d; ++ j)
		{
			scanf("%d", &x);
			add_edge(calc(3, i), calc(4, x), 1);
		}
	}
	for (int i = 1; i <= n; ++ i) add_edge(calc(2, i), calc(3, i), 1);
	for (int i = 1; i <= D; ++ i) add_edge(calc(4, i), T, 1);
	printf("%d", dinic());
	return 0;
} 

最长递增子序列问题

#include <bits/stdc++.h>
using namespace std;
const int N = 1005, M = 250000 * 2 + 10;
const int inf = 0x3f3f3f3f;
int head[N], q[N], d[N], cur[N], dp[N];
int cnt = -1, n, S, T, a[N];
vector<int> b[505];
struct edge
{
	int to, nxt, w;
}e[M];
void add_edge(int u, int v, int w)
{
	e[++ cnt].nxt = head[u], e[cnt].to = v, e[cnt].w = w, head[u] = cnt;
	e[++ cnt].nxt = head[v], e[cnt].to = u, e[cnt].w = 0, head[v] = cnt;
	return ;
}
bool bfs()
{
	int tt = 0, hh = 1;
	for (int i = 0; i <= T; ++ i) d[i] = -1;
	cur[S] = head[S], q[++ tt] = S, d[S] = 1;
	while(tt <= hh)
	{
		int x = q[tt ++];
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w)
			{
				d[y] = d[x] + 1;
				if(y == T) return true;
				cur[y] = head[y];
				q[++ hh] = y;
			}
		}
	}
	return false;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; flow < lim && i != - 1; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w)
		{
			int tt = dfs(y, min(e[i].w, lim - flow));
			if(tt == 0) d[y] = -1;
			e[i].w -= tt, e[i ^ 1].w += tt;
			flow += tt;
		}
	}
	return flow;
}
int dinic()
{
	int flow = 0, sum = 0;
	while(bfs()) while(flow = dfs(S, inf)) sum += flow;
	return sum;
}
int main()
{
	scanf("%d", &n);
	memset(head, - 1, sizeof head);
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
	S = 0, T = 2 * n + 1;
	for (int i = 1; i <= n; ++ i) add_edge(2 * i - 1, 2 * i, 1);
	int ans1 = 0, ans2 = 0, ans3 = 0;
	for (int i = 1; i <= n; ++ i)
	{
		dp[i] = 1;
		for (int j = 1; j <= i - 1; ++ j)
		{
			if(a[j] <= a[i] && dp[i] <= dp[j] + 1) dp[i] = dp[j] + 1;
		}
		for (int j = 1; j <= i - 1; ++ j)
		{
			if(a[j] <= a[i] && dp[i] == dp[j] + 1) add_edge(2 * j, 2 * i - 1, 1);
		}
		ans1 = max(ans1, dp[i]);
	}
	for (int i = 1; i <= n; ++ i)
	{
		if(dp[i] == 1) add_edge(S, 2 * i - 1, 1);
		if(dp[i] == ans1) add_edge(2 * i, T, 1);	
	}
	ans2 = dinic();
	for (int i = head[S]; i != -1; i = e[i].nxt)
	{
		if(e[i].to == 1 * 2 - 1) e[i].w = inf, e[i ^ 1].w = 0; 
	}
	for (int i = head[1 * 2 - 1]; i != -1; i = e[i].nxt)
	{
		if(e[i].to == 1 * 2) e[i].w = inf, e[i ^ 1].w = 0;
	}
	for (int i = head[n * 2 - 1]; i != -1; i = e[i].nxt)
	{
		if(e[i].to == n * 2) e[i].w = inf, e[i ^ 1].w = 0;
	}
	for (int i = head[n * 2]; i != -1; i = e[i].nxt)
	{
		if(e[i].to == T) e[i].w = inf, e[i ^ 1].w = 0;
	}
	ans3 = ans2 + dinic();
	printf("%d\n%d\n", ans1, ans2); 
	if(ans1 == 1) printf("%d\n", n);
	else printf("%d", ans3);
	return 0;
}

企鹅游行

可以把企鹅看成流量,至于起跳点次数的限制需要用拆点来限制。

点数:100 * 2 + 2 = 202

边数:(100 * 100 + 100 + 100 +100) * 2 = 20600

#include <bits/stdc++.h>
using namespace std;
const int N = 210, M = 20605, inf = INT_MAX;
int n, cnt = 0, S = 0, T, peg = 0, d[N], cur[N];
double D;
struct edge
{
	int to, w, nxt;
}e[M];
struct node
{
	int x, y;
}p[N];
int head[N];
void add(int u, int v, int w)
{
	e[cnt].nxt = head[u], e[cnt].w = w, e[cnt].to = v, head[u] = cnt ++;
	e[cnt].nxt = head[v], e[cnt].w = 0, e[cnt].to = u, head[v] = cnt ++;
	return ;
}
bool bfs()
{
	queue<int> q;
	for (int i = 0; i <= n + n; ++ i) d[i] = -1;
	q.push(S), d[S] = 0, cur[S] = head[S];
	while(!q.empty())
	{
		int x = q.front();
		q.pop();
		if(x == T) return true;
		for (int i = head[x]; i != - 1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w > 0)
			{
				d[y] = d[x] + 1;
				cur[y] = head[y];
				q.push(y);
			}
		}
	}
	return false;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w > 0)
		{
			int t = dfs(y, min(lim - flow, e[i].w));
			if(!t) d[y] = - 1;
			flow += t;
			e[i].w -= t, e[i ^ 1].w += t;
		}
	}
	return flow;
}
int dinic()
{
	int sum = 0, flow = 0;
	while(bfs()) while(flow = dfs(S, inf)) sum += flow;
	return sum;
}
bool check(int i, int j)
{
	double y = p[i].y - p[j].y;
	double x = p[i].x - p[j].x;
	return x * x + y * y < D * D;
}
int main()
{
	int cases;
	scanf("%d", &cases);
	while(cases --)
	{
		scanf("%d %lf", &n, &D);
		memset(head, - 1, sizeof head); 
		cnt = 0, peg = 0;
		for (int i = 1; i <= n; ++ i)
		{
			int x, y, a, b;
			scanf("%d %d %d %d", &x, &y, &a, &b);
			p[i] = ((node){x, y});
			add(S, i, a);
			add(i, i + n, b);
			peg += a;
		}
		for (int i = 1; i <= n; ++ i)
		{
			for (int j = i + 1; j <= n; ++ j)
			{
				if(check(i, j)) add(i + n,  j, inf), add(j + n, i, inf);
			}
		}
		bool pd = false; 
		for (int i = 1; i <= n; ++ i)
		{
			T = i;
			for (int j = 0; j < cnt; j += 2) e[j].w += e[j ^ 1].w, e[j ^ 1].w = 0;
			if(dinic() == peg) printf("%d ", i - 1), pd = true; 
		}
		if(pd) printf("\n");
		else printf("-1\n");
	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int M = 40205, N = 105;
int S = 0, T;
int m, n, head[N], cnt = 0, cur[N], d[N], pre[1010], pig[1010];
bool vis[N][N];
struct edge
{
	int to, nxt, w;
}e[M];
void add(int u, int v, int w)
{
	e[cnt].w = w, e[cnt].to = v, e[cnt].nxt = head[u], head[u] = cnt ++;
	e[cnt].w = 0, e[cnt].to = u, e[cnt].nxt = head[v], head[v] = cnt ++;
	return ;
}
bool bfs()
{
	queue<int> q;
	for (int i = 0; i <= n + 1; ++ i) d[i] = -1;
	cur[S] = head[S], d[S] = 1, q.push(S);
	while(!q.empty())
	{
		int x = q.front();
		q.pop();
		if(x == T) return true;
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w > 0)
			{
				d[y] = d[x] + 1;
				q.push(y);
				cur[y] = head[y];
			}
		}
	}
	return false;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w > 0)
		{
			int t = dfs(y, min(e[i].w, lim - flow));
			if(!t) d[y] = -1;
			flow += t;
			e[i].w -= t, e[i ^ 1].w += t;
		}
	}
	return flow;
}
int dinic()
{
	int flow = 0, sum = 0;
	while(bfs()) while(flow = dfs(S, inf)) sum += flow;
	return sum;
}
int main()
{
	scanf("%d %d", &m, &n);
	memset(head, -1, sizeof head);
	S = 0, T = n + 1;
	for (int i = 1; i <= m; ++ i) scanf("%d", &pig[i]);
	for (int i = 1; i <= n; ++ i)
	{
		int a, k, val = 0;
		scanf("%d", &a);
		for (int j = 1; j <= a; ++ j)
		{
			scanf("%d", &k);
			if(!pre[k]) val += pig[k], pre[k] = i;
			else if(!vis[pre[k]][i]) add(pre[k], i, inf), vis[pre[k]][i] = true, pre[k] = i;
		}
		add(S, i, val);
		scanf("%d", &a);
		add(i, T, a);
	}
	printf("%d", dinic());
	return 0;
}

Dinic/ISAP求最小割

#include <bits/stdc++.h>
using namespace std;
const int N = 10005, M = 200005, inf = 0x3f3f3f3f;
int n, m, cnt = 0, head[N], d[N], cur[N], S, T;
struct edge
{
	int to, nxt, w;
}e[M];
void add(int u, int v, int w)
{
	e[cnt].to = v, e[cnt].w = w, e[cnt].nxt = head[u], head[u] = cnt ++;
	e[cnt].to = u, e[cnt].w = 0, e[cnt].nxt = head[v], head[v] = cnt ++;
	return ; 
}
bool bfs()
{
	queue<int> q;
	for (int i = 0; i <= n; ++ i) d[i] = -1;
	q.push(S), d[S] = 0, cur[S] = head[S];
	while(!q.empty())
	{
		int x = q.front();
		q.pop();
		for (int i = head[x]; i != - 1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w > 0)
			{
				d[y] = d[x] + 1;
				cur[y] = head[y];
				if(y == T) return true;
				q.push(y);
			}
		}
	}
	return false;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w > 0)
		{
			int t = dfs(y, min(e[i].w, lim - flow));
			if(!t) d[y] = -1;
			flow += t;
			e[i].w -= t, e[i ^ 1].w += t;
		}
	}
	return flow; 
}
int dinic()
{
	int flow = 0, sum = 0;
	while(bfs()) while(flow = dfs(S, inf)) sum += flow;
	return sum;
}
int main()
{
	scanf("%d %d %d %d", &n, &m, &S, &T);
	memset(head, - 1, sizeof head);
	for (int i = 1; i <= m; ++ i)
	{
		int u, v, w; 
		scanf("%d %d %d", &u, &v, &w);
		add(u, v, w);
	}	
	printf("%d", dinic());
	return 0;
}

网络战争

需要采用01分数规划的方法,二分平均值,然后判断最小割的边权和是不是小于等于零,但是要注意的问题是,流量为负数显然是不合理的,为了让答案尽可能的小,我们自动选完所有边权 <= 0的,然后再跑最小割。

#include <bits/stdc++.h>
using namespace std;
typedef double db;
const db inf = 1000000000.0, eps = 1e-9;
const int N = 105, M = 805;
int n, m, S, T, cnt = 0, head[N], d[N], cur[N];
struct edge
{
	int to, nxt;
	db w;
}e[M], ee[M];
void add_edge(int u, int v, db w)
{
	ee[cnt].to = v, ee[cnt].nxt = head[u], ee[cnt].w = w, head[u] = cnt ++;
	ee[cnt].to = u, ee[cnt].nxt = head[v], ee[cnt].w = 0, head[v] = cnt ++;
	return ;
}
bool bfs()
{
	for (int i = 1; i <= n; ++ i) d[i] = -1;
	queue<int> q;
	d[S] = 1, q.push(S), cur[S] = head[S];
	while(!q.empty())
	{
		int x = q.front();
		q.pop();
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w > eps)
			{
				d[y] = d[x] + 1;
				cur[y] = head[y];
				if(y == T) return true;
				q.push(y);
			}
		}
	}
	return false;
}
db dfs(int x, db lim)
{
	if(x == T) return lim;
	db flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w > eps)
		{
			db t = dfs(y, min(lim - flow, e[i].w));
			if(t <= eps) d[y] = -1;
			flow += t;
			e[i].w -= t, e[i ^ 1].w += t;
 		}
	}
	return flow;
}
db dinic()
{
	db sum = 0, flow = 0;
	while(bfs()) while(flow = dfs(S, inf)) sum += flow;
	return sum;
}
db l = 0.0, r = 1000000000.0, mid, ans = 0, sum = 0;
int main()
{
	scanf("%d %d %d %d", &n, &m, &S, &T);
	memset(head, -1, sizeof(head));
	for (int i = 1; i <= m; ++ i)
	{
		int a, b;
		db w;
		scanf("%d %d %lf", &a, &b, &w);
		add_edge(a, b, w);
	}
	while(r - l >= 0.0001)
	{
		mid = (l + r) / 2;
		sum = 0.0;
		for (int i = 0; i < cnt; i += 2) 
		{
			e[i] = ee[i], e[i ^ 1] = ee[i ^ 1];
			if(e[i].w <= mid) sum = sum + e[i].w - mid, e[i].w = 0, e[i ^ 1].w = 0;
			else e[i].w -= mid, e[i ^ 1].w = e[i].w;	 
		}
		sum += dinic();
		if(sum <= eps) ans = mid, r = mid;
		else l = mid;
	}
	printf("%.2lf", ans);
	return 0;
}

最优标号

如果不希望把一条边变成割集的话,我们直接把这条边的容量设置为正无穷并且与源点或者汇点相连接就可以了。

这道题对每一位分别求解最小割。

#include <bits/stdc++.h>
using namespace std;
const int N = 505, M = 6005, inf = 0x3f3f3f3f;
int n, m, cnt = 0, cur[N], d[N], head[N], S, T;
typedef long long ll;
pair<int, int> p[N], E[M];
struct edge
{
	int to, nxt, w;
}e[M];
void add_edge(int u, int v, int c, int d)
{
	e[cnt].to = v, e[cnt].w = c, e[cnt].nxt = head[u], head[u] = cnt ++;
	e[cnt].to = u, e[cnt].w = d, e[cnt].nxt = head[v], head[v] = cnt ++;
	return ;
}
bool bfs()
{
	queue<int> q;
	for (int i = 0; i <= n + 1; ++ i) d[i] = -1;
	q.push(S), d[S] = 0, cur[S] = head[S];
	while(!q.empty())
	{
		int x = q.front();
		q.pop();
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w > 0)
			{
				d[y] = d[x] + 1;
				cur[y] = head[y];
				if(y == T) return true;
				q.push(y);
			}
		}
	}
	return false;
}
int dfs(int x, int lim)
{
	
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w > 0)
		{
			int t = dfs(y, min(lim - flow, e[i].w));
			if(!t) d[y] = -1;
			flow += t;
			e[i].w -= t, e[i ^ 1].w += t;
		}
	}
	return flow;
}
int dinic()
{
	int sum = 0, flow = 0;
	while(bfs()) while(flow = dfs(S, inf)) sum += flow;
	return sum;	
}
int main()
{
	scanf("%d %d", &n, &m);
	S = 0, T = n + 1;
	for (int i = 1; i <= m; ++ i) scanf("%d %d", &E[i].first, &E[i].second);
	int k;
	scanf("%d", &k);
	for (int i = 1; i <= k; ++ i) scanf("%d %d", &p[i].first, &p[i].second);
	ll ans = 0;
	for (int i = 0; i <= 30; ++ i)
	{
		cnt = 0;
		for (int j = 0; j <= n + 1; ++ j) head[j] = -1;
		for (int j = 1; j <= m; ++ j) add_edge(E[j].first, E[j].second, 1, 1);
		for (int j = 1; j <= k; ++ j)
		{
			if((p[j].second >> i) & 1)	add_edge(S, p[j].first, inf, 0);
			else add_edge(p[j].first, T, inf, 0);
		} 
	
		int num = dinic();
		ans += (1ll << i) * num; 
	}
	printf("%lld", ans);
	return 0;
}

最大获利

#include <bits/stdc++.h>
using namespace std;
const int N = 55005, M = 310005, inf = 0x3f3f3f3f;
struct edge
{
	int to, nxt, w;
}e[M];
int n, m, cnt = 0, cur[N], head[N], d[N], S, T, sum = 0;
void add(int u, int v, int w)
{
	e[cnt].to = v, e[cnt].nxt = head[u], e[cnt].w = w, head[u] = cnt ++;
	e[cnt].to = u, e[cnt].nxt = head[v], e[cnt].w = 0, head[v] = cnt ++;
	return ;
}
bool bfs()
{
	queue<int> q;
	for (int i = 0; i <= T; ++ i) d[i] = -1;
	d[S] = 0, q.push(S), cur[S] = head[S];
	while(!q.empty())
	{
		int x = q.front();
		q.pop();
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w > 0)
			{
				d[y] = d[x] + 1;
				cur[y] = head[y];
				if(y == T) return true;
				q.push(y);
			} 
		}
	} 
	return false;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0 ;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w > 0)
		{
			int t = dfs(y, min(lim - flow, e[i].w));
			if(!t) d[y] = -1;
			flow += t;
			e[i].w -= t, e[i ^ 1].w += t;
		}
	}
	return flow;
}
int dinic()
{
	int flow = 0, ans = 0;
	while(bfs()) while(flow = dfs(S, inf)) ans += flow;
	return ans;
}
int main()
{
	scanf("%d %d", &n, &m);
	memset(head, -1, sizeof head);
	S = 0, T = n + m + 1;
	for (int i = 1; i <= n; ++ i)
	{
		int p;
		scanf("%d", &p);
		add(i, T, p);
	}	
	for (int i = 1; i <= m; ++ i)
	{
		int a, b, c;
		scanf("%d %d %d", &a, &b, &c);
		add(i + n, a, inf);
		add(i + n, b, inf);
		add(S, i + n, c); 
		sum += c;
	}
	printf("%d", sum - dinic());
}

Hard Life生活的艰辛/最大密度子图模板

#include <bits/stdc++.h>
using namespace std;
const int N = 1105, M = 10005;
typedef long double db;
const db eps = 0.000000001;
const db inf = 1000000000.0;
int n, m, head[N], cur[N], d[N], S, T, tot = 0, cnt = 0;
vector<int> k;
bool vis[N];
struct edge
{
	int to, nxt;
	db w;
	bool opt;
}e[M];
void build(db mid)
{
	for (int i = 0; i < cnt; i += 2)
	{
		if(e[i].opt == true) e[i].w = mid, e[i ^ 1].w = 0;
		else e[i].w += e[i ^ 1].w, e[i ^ 1].w = 0;
	}
	return ;
}
void solve(int x)
{
	vis[x] = 1;
	if(1 <= x && x <= n) k.push_back(x);
	for (int i = head[x]; i != -1; i = e[i].nxt)
	{
		int y = e[i].to;
		if(vis[y] || e[i].w <= eps) continue;
		solve(y);
	}
	return ;
}
void add_edge(int u, int v, db w, bool opt)
{
	e[cnt].nxt = head[u], e[cnt].w = w, e[cnt].to = v, e[cnt].opt = opt, head[u] = cnt ++;
	e[cnt].nxt = head[v], e[cnt].w = 0, e[cnt].to = u, e[cnt].opt = opt, head[v] = cnt ++;
	return ;	
} 
bool bfs()
{
	queue<int> q;
	q.push(S);
	for (int i = 0; i <= m + n + 1; ++ i) d[i] = -1;
	cur[S] = head[S], d[S] = 0, q.push(S);
	while(!q.empty())
	{
		int x = q.front();
		q.pop();
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w > eps)
			{
				d[y] = d[x] + 1;
				cur[y] = head[y];
				if(y == T) return true;
				q.push(y);
			}
		}
	} 
	return false;
}
db dfs(int x, db lim)
{
	if(x == T) return lim;
	db flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		cur[x] = i;
		int y = e[i].to;
		if(d[y] == d[x] + 1 && e[i].w > eps)
		{
			db t = dfs(y, min(lim - flow, e[i].w));
			if(t <= eps) d[y] = -1;
			flow += t;
			e[i].w -= t, e[i ^ 1].w += t;
		}
	}
	return flow;
}
db dinic()
{
	db flow = 0, sum = 0;
	while(bfs()) while((flow = dfs(S, inf)) > eps) sum += flow;
	return sum;
}
int main()
{
	scanf("%d %d", &n, &m);
	S = 0, T = n + m + 1;
	memset(head, - 1, sizeof(head));
	db sum = 1.0 * m;
	for (int i = 1; i <= m; ++ i)
	{
		int a, b;
		scanf("%d %d", &a, &b);
		add_edge(S, i + n, 1, 0);
		add_edge(i + n, b, inf, 0);
		add_edge(i + n, a, inf, 0);	
	}	
	for (int i = 1; i <= n; ++ i) add_edge(i, T, -1, 1);
	db l = 0.0, r = 1000.0, mid, ans;
	while(r - l >= 0.0001)
	{
		mid = (l + r) / 2.0;
		build(mid);
		if(sum - dinic() > 0.0) ans = mid, l = mid;
		else r = mid;
	}
	build(ans);
	dinic();
	solve(S);
	if(m == 0) k.push_back(1);
	sort(k.begin(), k.end());
	printf("%d\n", k.size());
	for (int i = 0; i < k.size(); ++ i) printf("%d\n", k[i]);
	return 0;
} 

Destroying The Graph 有向图破坏

#include <bits/stdc++.h>
using namespace std;
const int N = 205, M = 10405, inf = 0x3f3f3f3f;
int n, m, S, T, a[N], b[N], head[N], cur[N], d[N], cnt = 0;
bool vis[N][N];
struct edge
{
	int to, nxt, w;
}e[M];
void add_edge(int u, int v, int w)
{
	e[cnt].to = v, e[cnt].nxt = head[u], e[cnt].w = w, head[u] = cnt ++;
	e[cnt].to = u, e[cnt].nxt = head[v], e[cnt].w = 0, head[v] = cnt ++;
	return ;
}
bool bfs()
{
	queue<int> q;
	for (int i = 0; i <= T; ++ i) d[i] = -1;
	q.push(S), cur[S] = head[S], d[S] = 0;
	while(!q.empty())
	{
		int x = q.front(); q.pop();
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w)
			{
				d[y] = d[x] + 1;
				cur[y] = head[y];
				q.push(y);
				if(y == T) return true;
			}
		}
	}
	return false;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i =e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w > 0)
		{
			int t = dfs(y, min(lim - flow, e[i].w));
			if(!t) d[y] = -1;
			flow += t;
			e[i].w -= t, e[i ^ 1].w += t; 
		}
	}
	return flow;
}
int dinic()
{
	int flow = 0, sum = 0;
	while(bfs()) while(flow = dfs(S, inf)) sum += flow;
	return sum;
}
int main()
{
	scanf("%d %d", &n, &m);
	memset(head, - 1, sizeof head);
	S = 0, T = n + n + 1;
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
	for (int i = 1; i <= n; ++ i) scanf("%d", &b[i]);
	for (int i = 1; i <= m; ++ i)
	{
		int x, y;
		scanf("%d %d", &x, &y);
		if(vis[x][y]) continue;
		add_edge(x, y + n, inf);
	}
	for (int i = 1; i <= n; ++ i) add_edge(S, i, b[i]), add_edge(i + n, T, a[i]);
	printf("%d", dinic());
	return 0;
}

王者之剑

#include <bits/stdc++.h>
using namespace std;
const int N = 10005, inf = 0x3f3f3f3f, M = 60005;
int n, m, val[105][105], sum = 0, head[N], cnt = 0, S, T, d[N], cur[N];
struct edge
{
	int to, nxt, w;
}e[M];
bool check(int i, int j)
{
	if(i & 1) 
	{
		if(j & 1) return 1;
		else return 0;
	}
	else
	{
		if(j & 1) return 0;
		else return 1;
	}
}
inline int id(int i, int j)
{
	return (i - 1) * m + j;
}
int rx[5] = {- 1, 1, 0, 0};
int ry[5] = {0, 0, - 1, 1};
void add_edge(int u, int v, int w)
{
	e[cnt].to = v, e[cnt].w = w, e[cnt].nxt = head[u], head[u] = cnt ++;
	e[cnt].to = u, e[cnt].w = 0, e[cnt].nxt = head[v], head[v] = cnt ++;
	return ; 
}
bool bfs()
{
	queue<int> q;
	for (int i = 0; i <= T; ++ i) d[i] = -1;
	q.push(S), cur[S] = head[S], d[S] = 0;
	while(!q.empty())
	{
		int x = q.front();
		q.pop();
		for (int i = head[x]; i != - 1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(d[y] == -1 && e[i].w > 0)
			{
				d[y] = d[x] + 1;
				cur[y] = head[y];
				q.push(y);
				if(y == T) return true;
			}
		}
	}
	return false;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	int flow = 0;
	for (int i = cur[x]; i != - 1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(d[y] == d[x] + 1 && e[i].w > 0)
		{
			int t = dfs(y, min(lim - flow, e[i].w));
			if(!t) d[y] = -1;
			flow += t;
			e[i].w -= t, e[i ^ 1].w += t;
		}
	}
	return flow;
}
int dinic()
{
	int flow = 0, sum = 0;
	while(bfs()) while(flow = dfs(S, inf)) sum += flow;
	return sum;
}

int main()
{
	scanf("%d %d", &n, &m);
	S = 0, T = n * m + 1;
	memset(head, - 1, sizeof head);
	for (int i = 1; i <= n; ++ i)
	{
		for (int j = 1; j <= m; ++ j) scanf("%d", &val[i][j]), sum += val[i][j];
	}	
	for (int i = 1; i <= n; ++ i)
	{
		for (int j = 1; j <= m; ++ j)
		{
			int a, b;
			a = id(i, j);
			for (int k = 0; k < 4; ++ k)
			{
				int x = i + rx[k], y = j + ry[k];
				if(x <= 0 || y <= 0 || x > n || y > m) continue;
				b = id(x, y);
				if(check(i, j) == 0) add_edge(a, b, inf);
				else add_edge(b, a, inf);
			}
			if(check(i, j) == 0) add_edge(S, a, val[i][j]);
			else add_edge(a, T, val[i][j]);
		}
	}
	printf("%d", sum - dinic());
	return 0;
}

最小费用流(模板)

#include <bits/stdc++.h>
using namespace std;
const int N = 405, M = 30005, inf = 0x3f3f3f3f;
int n, m, f = 0, dis[N], pre[N], cur[N], T, sum = 0, ans1 = 0, ans2 = 0, vis[N];
struct edge
{
	int to, nxt, w, c;
}e[M];
int cnt = 0, head[N];
void add_edge(int u, int v, int w, int c)
{
	e[cnt].to = v, e[cnt].w = w, e[cnt].c = c, e[cnt].nxt = head[u], head[u] = cnt ++;
	e[cnt].to = u, e[cnt].w = 0, e[cnt].c = -c, e[cnt].nxt = head[v], head[v] = cnt ++;
	return ; 
}
bool spfa()
{
	queue<int> q;
	for (int i = 1; i <= n; ++ i) dis[i] = inf;
	q.push(1), dis[1] = 0, vis[1] = 1, cur[1] = head[1];
	while(!q.empty())
	{
		int x = q.front(); q.pop();
		vis[x] = 0;
		for (int i = head[x]; i != -1; i = e[i].nxt)
		{
			int y = e[i].to;
			if(dis[y] > dis[x] + e[i].c && e[i].w > 0)
			{
				dis[y] = dis[x] + e[i].c, cur[y] = head[y];
				if(!vis[y]) vis[y] = 1, q.push(y);
			}
		}	
	} 
	for (int i = 1; i <= n; ++ i) vis[i] = 0;
	if(dis[T] == inf) return false;
	return true;
}
int dfs(int x, int lim)
{
	if(x == T) return lim;
	vis[x] = true;
	int flow = 0;
	for (int i = cur[x]; i != -1 && flow < lim; i = e[i].nxt)
	{
		int y = e[i].to;
		cur[x] = i;
		if(dis[y] == dis[x] + e[i].c && e[i].w > 0 && !vis[y])
		{
			int t = dfs(y, min(lim - flow, e[i].w));
			if(!t) dis[y] = inf;
			else
			{
				flow += t, ans2 = ans2 + t * e[i].c;
				e[i].w -= t, e[i ^ 1].w += t;
			}
		}
	}
	vis[x] = false;
	return flow; 
}
void dinic()
{
	int flow = 0;
	while(spfa()) while(flow = dfs(1, inf)) ans1 += flow;
	return ;
}
int main()
{
	scanf("%d %d", &n, &m);
	T = n;
	memset(head, -1, sizeof head);
	for (int i = 1; i <= m; ++ i)
	{
		int u, v, w, c;
		scanf("%d %d %d %d", &u, &v, &w, &c);
		add_edge(u, v, w, c);
	}
	dinic();
	printf("%d %d", ans1, ans2);
	return 0;
}

posted @ 2025-02-13 10:41  Helioca  阅读(13)  评论(0)    收藏  举报
Document