SGU 194 Reactor Cooling (无源汇有上下界的最大流)

Description

给出一个\(N\)个点\(M\)条边的循环网络,每条边有一个流量下限和上限,问是否有满足容量限制的最大流,若有,输出每条边上的流量。

Input

第一行给出结点数\(N\)和边数\(M\),接下来\(M\)行,每行给出四个数\(u\)\(v\)\(l\)\(c\),表示\(u\)\(v\)有一条下限为\(l\)上限为\(c\)的边。\(1 \leqslant N \leqslant 200\)

Output

如果有可行的最大流,输出"YES",接下来\(M\)行,每行一个整数,输出每条边上的流量,按输入的顺序给出。如果没有,输出"NO"。

Sample Input

4 6 
1 2 1 3 
2 3 1 3 
3 4 1 3 
4 1 1 3 
1 3 1 3 
4 2 1 3 

Sample Output

YES 
1 
2 
3 
2 
1 
1 

Solution

无源汇带上下界的最大流问题。转化为没有下限的网络流问题,对于原图中一条下限为\(l\)上限为\(c\)的边,建一条下限为\(0\),上限为\(c-l\)的边。对于每个点\(i\),令\(du[i]=\)流入i的所有下限之和-流出i的所有下限之和,建立源点\(s\)和汇点\(t\),对于每个结点\(i\),如果\(du[i]>0\),建一条从\(s\)\(i\)的容量为\(du[i]\)的边,如果\(du[i]<0\),建一条从\(i\)\(t\)的容量为\(du[i]\)的边,从\(s\)\(t\)跑一遍最大流,如果满流,则说明有从可行的最大流,反之没有。

每条边上的真实流量=这条边上的流量下界+新图中边上的流量。新图中边上的流量刚好记录再这条边的反向弧中。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
const int INF = 0x7f7f7f7f;
const int N = 200 + 10;
const int M = 4e4 + 10;

struct Edge
{
	int to, c, next;
	Edge() {}
	Edge(int to, int c, int next) : to(to), c(c), next(next) {}
} edge[M];
int adj[N], tot;

void init()
{
	memset(adj, -1, sizeof(adj));
	tot = 0;
}

void add(int u, int v, int c)
{
	edge[tot] = Edge(v, c, adj[u]);
	adj[u] = tot++;
	edge[tot] = Edge(u, 0, adj[v]);
	adj[v] = tot++;
}

int level[N];
queue<int> q;
bool bfs(int s, int t)
{
	while (!q.empty()) q.pop();
	memset(level, -1, sizeof(level));
	level[s] = 0; q.push(s);
	while (!q.empty())
	{
		int u = q.front(); q.pop();
		for (int i = adj[u]; i != -1; i = edge[i].next)
		{
			Edge &e = edge[i];
			if (e.c && level[e.to] == -1)
			{
				level[e.to] = level[u] + 1;
				if (e.to == t) return true;
				q.push(e.to);
			}
		}
	}
	return false;
}

int cur[N];
int dfs(int u, int t, int flow)
{
	if (u == t) return flow;
	for (int &i = cur[u]; i != -1; i = edge[i].next)
	{
		Edge &e = edge[i];
		if (e.c && level[e.to] > level[u])
		{
			int f = dfs(e.to, t, min(flow, e.c));
			if (f)
			{
				e.c -= f;
				edge[i ^ 1].c += f;
				return f;
			}
		}
	}
	return 0;
}

int dinic(int s, int t)
{
	int flow = 0;
	while (bfs(s, t))
	{
		memcpy(cur, adj, sizeof(adj));
        int f;
		while (f = dfs(s, t, INF)) flow += f;
	}
	return flow;
}

int du[N], down[N];

int main()
{
	int n, m;
	scanf("%d%d", &n, &m);
	init();
	int s = 0, t = n + 1;
	memset(du, 0, sizeof(du));
	for (int i = 0; i < m; i++)
	{
		int u, v, b, c;
		scanf("%d%d%d%d", &u, &v, &b, &c);
		add(u, v, c - b);
		du[u] -= b; du[v] += b;
		down[i] = b;
	}
	int sum = 0;
	for (int i = 1; i <= n; i++)
	{
		if (du[i] > 0) add(s, i, du[i]), sum += du[i];
		else if (du[i] < 0) add(i, t, -du[i]);
	}
	if (dinic(s, t) < sum) return printf("NO\n"), 0;
	printf("YES\n");
	for (int i = 0; i < m; i++) printf("%d\n", down[i] + edge[2 * i + 1].c);
	return 0;
}

https://vjudge.net/problem/SGU-194

posted @ 2017-08-15 10:26  达达Mr_X  阅读(237)  评论(0)    收藏  举报