题意:每台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;
}