POJ3436-ACM Computer Factory(最大流)

题意:每台ACM电脑都由P个零件组成。当一台电脑的每个零件都有的时候,那么这台电脑就可以拿来参赛了。电脑工厂准备用N台机器来生成这些电脑,每台电脑会接受一些零件不足的半成品,并生产出一台电脑,这台电脑可能是完成品或者是半成品。每台机器的效率由它的每单位时间生成的电脑数量,输入规格和输出规格所决定。规格由P个整数所描述,0表示这个零件不需要,1表示这个零件需要,2表示这个零件可有可无。输出规格也同样。每台机器由一些生产线相连,ACM协会决定重新摆放生产线来使得每小时生成的电脑数量最多。

输入:输入由P,N组成,N表示有N台机器,接下来是N行机器的规格描述,每行有2 * p + 1个整数,(Qi,Si_1,Si_2...Si_p,Di_1,Di_2...Di_p),表示单位时间内生成的电脑数量,输入规格和输出规格。对于一台机器的输入规格,只能和另一台机器的输出规格相匹配,它们才能由生产线相连。

输出:输出最大的单位时间内的生产数量。然后输出M,表示相连的方案数,并输出具体的方案。

分析:最大流问题,我采用的是邻接表的方式建图,考虑建图方式,首先的一个是容量限制,每台机器具有一个生成效率,因此需要拆成两个点,输出点为(i + n),输入点为(i),然后连一条(容量为Q)的边。1.每台机器的输出点向符和的输入点的机器连一条容量为inf的边。2.建立一个超级汇点,从汇点向每台机器的输入规格为("000..."或者"若干个0和若干个2")的机器连一条容量为(inf)的边3.建立一个超级源点,输出规模为全1的机器向它连一套容量为"inf"的边。然后求从起点到终点的最大流。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <algorithm>

using namespace std;

const int N = 55;
const int M = N * N + 4 * N;
const int inf = 1 << 29;

struct Node
{
	int in[15], out[15], q;
}ma[N];

int h[4 * N], e[2 * M], ne[2 * M], idx;
int w[2 * M];

int incf[4 * N], pre[4 * N];
bool st[4 * N];

//p个零件,n台机器
int p, n;
int s, t, maxflow;

void add(int a, int b, int c)
{
	e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
	e[idx] = a, w[idx] = 0, ne[idx] = h[b], h[b] = idx++;
}

bool bfs()
{
	memset(st, 0, sizeof st);
	stack<int> q;
	q.push(s);
	st[s] = true;
	incf[s] = inf;

	while (q.size())
	{
		int u = q.top();
		q.pop();

		for (int i = h[u]; i != -1; i = ne[i])
		{
			if (w[i])
			{
				int j = e[i];
				if (st[j]) continue;
				incf[j] = min(incf[u], w[i]);
				pre[j] = i;
				q.push(j), st[j] = true;
				if (j == t) return true;
			}
		}
	}
	return false;
}

void update()
{
	int u = t;
	while (u != s)
	{
		int i = pre[u];
		w[i] -= incf[t];
		w[i ^ 1] += incf[t];
		u = e[i ^ 1];
	}
	maxflow += incf[t];
}

struct re
{
	int a, b, c;
	re(int a, int b, int c):a(a), b(b), c(c){}
};

int main()
{
	scanf("%d%d", &p, &n);
	memset(h, -1, sizeof h);
	idx = 0, maxflow = 0;

	for (int i = 1; i <= n; ++i)
	{
		scanf("%d", &ma[i].q);
		for (int j = 1; j <= p; ++j) scanf("%d", &ma[i].in[j]);
		for (int j = 1; j <= p; ++j) scanf("%d", &ma[i].out[j]);
	}

	s = 0, t = 2 * n + 1;

	//拆点,点上有容量限制
	for (int i = 1; i <= n; ++i)
	{
		add(i, i + n, ma[i].q);
	}

	//源点到各点
	for (int i = 1; i <= n; ++i)
	{
		bool flag = true;
		for (int j = 1; j <= p; ++j)
		{
			if (ma[i].in[j] == 1)
			{
				flag = false;
				break;
			}
		}
		if (flag)
		{
			add(0, i, inf);
		}
	}

	//各点到汇点
	for (int i = 1; i <= n; ++i)
	{
		bool flag = true;
		for (int j = 1; j <= p; ++j)
		{
			if (ma[i].out[j] != 1)
			{
				flag = false;
				break;
			}
		}
		if (flag)
		{
			add(i + n, t, inf);
		}
	}

	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= n; ++j)
		{
			bool flag = true;
			for (int k = 1; k <= p; ++k)
			{
				if (!(ma[i].out[k] == ma[j].in[k] || ma[j].in[k] == 2))
				{
					flag = false;
					break;
				}
			}
			if (flag)
			{
				add(i + n, j, inf);
			}
		}			
	}

	while (bfs()) update();

	printf("%d ", maxflow);

	vector<re> v;
	for (int i = 0; i <= idx; i += 2)
	{
		int b = e[i], a = e[i ^ 1], c = w[i];
		if (b > n) continue;
		if (a <= n) continue;
		if (a == 0) continue;
		if (inf - c)
		{
			v.push_back(re(a - n, b, inf - c));
		}
	}

	printf("%d
", v.size());
	for (int i = 0; i < v.size(); ++i)
	{
		printf("%d %d %d
", v[i].a, v[i].b, v[i].c);
	}


	return 0;
}
原文地址:https://www.cnblogs.com/pixel-Teee/p/13298519.html