这题在寒假个人赛的时候出现过,当时还不会网络流直接就开始 DFS 。
题意
一台电脑有 p 个零件,现在有个工厂有 m 个工作台。
每个工作台每秒可以加工 a 台电脑,并且对接受到的电脑有要求,要求通过 p 个数字给出:
如果第 i 个数字为 0 ,表示接收到的电脑不能包含第 i 个零件;
如果为 1,表示接收到的电脑必须包含第 i 个零件;
如果为 2,表示这个零件有没有都可以;
处理完后的电脑形态也通过 p 个数字给出:
如果第 i 个数字为 0,表示处理完之后没有零件 i
如果为 1,表示处理完之后有零件 i
现在问这个工厂每秒最多可以加工多少台电脑(即处理完后每个零件都存在),并输出路径。
题解
把每一个工作台拆成两个点:输入端和输出端,这两个点之间连一条边。
两层 for 循环枚举所有的工作台,如果第 i 台工作台处理完的电脑 可以供给给第 j 台电脑,那么第 i 台工作台的输出端,向第 j 台的输入端连一条边。
新建一个源点和汇点,源点向输入端要求为全 0 的连一条边,输出端全为 1 的向汇点连一条边,跑 Dinic 即可。
输出路径:先把所有的边保存一下,然后遍历输出端连向输入端的边,如果容量变小了,那么就输出该差值。
代码
/*
* @Autor: valk
* @Date: 2020-08-11 12:38:37
* @LastEditTime: 2020-09-15 19:15:02
* @Description: 如果邪恶 是华丽残酷的乐章 它的终场 我会亲手写上 晨曦的光 风干最后一行忧伤 黑色的墨 染上安详
*/
#include <algorithm>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod = 1e9 + 7;
const int seed = 12289;
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int N = 2e2 + 10;
struct parts {
int a[11], b[11], flow;
} parts[N];
struct Edge {
int to, cap, next;
Edge() {};
Edge(int _to, int _cap, int _next)
{
to = _to, cap = _cap, next = _next;
}
} edge[N * N], cpy[N * N];
struct out {
int u, v, cap;
out() {};
out(int _u, int _v, int _cap)
{
u = _u, v = _v, cap = _cap;
}
} rel[N * N];
int cnt, head[N];
void add(int u, int v, int cap)
{
edge[cnt] = Edge(v, cap, head[u]);
head[u] = cnt++;
}
int s, t, p, n;
int dep[N], cur[N];
int bfs()
{
memset(dep, -1, sizeof(dep));
memcpy(cur, head, sizeof(head));
queue<int> q;
q.push(s);
dep[s] = 0;
while (!q.empty()) {
int now = q.front();
q.pop();
for (int i = head[now]; i != -1; i = edge[i].next) {
int v = edge[i].to, cap = edge[i].cap;
if (cap && dep[v] == -1) {
dep[v] = dep[now] + 1;
q.push(v);
}
}
}
return dep[t] != -1;
}
int dfs(int u, int flow)
{
if (u == t)
return flow;
int rel = flow;
for (int i = head[u]; i != -1; i = edge[i].next) {
if (!rel)
break;
cur[u] = i;
int v = edge[i].to, cap = edge[i].cap;
if (dep[v] == dep[u] + 1 && cap) {
int tmp = dfs(v, min(rel, cap));
rel -= tmp;
edge[i].cap -= tmp;
edge[i ^ 1].cap += tmp;
}
}
return flow - rel;
}
void Dinic()
{
int ans = 0;
while (bfs()) {
ans += dfs(s, inf);
}
int num = 0;
for (int i = 1; i <= 2 * n + 2; i++) {
for (int j = head[i]; j != -1; j = edge[j].next) {
int v = edge[j].to, cap = edge[j].cap;
int _v = cpy[j].to, _cap = cpy[j].cap;
if (cap < _cap && i > n && i <= 2 * n && v <= n) {
rel[++num] = out(i - n, v, _cap - cap);
// printf("%d %d %d
", i - n, v, _cap - cap);
// printf("%d %d %d
", i > n ? i - n : i, v > n ? v - n : v, _cap - cap);
}
}
}
printf("%d %d
", ans, num);
for (int i = 1; i <= num; i++) {
printf("%d %d %d
", rel[i].u, rel[i].v, rel[i].cap);
}
}
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d", &p, &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &parts[i].flow);
for (int j = 1; j <= p; j++) {
scanf("%d", &parts[i].a[j]);
}
for (int j = 1; j <= p; j++) {
scanf("%d", &parts[i].b[j]);
}
add(i, n + i, parts[i].flow);
add(n + i, i, 0);
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i == j)
continue;
int flag = 1;
for (int k = 1; k <= p; k++) {
if (parts[j].a[k] == 2)
continue;
if (parts[i].b[k] != parts[j].a[k]) {
flag = 0;
break;
}
}
if (flag) {
add(n + i, j, parts[i].flow);
add(j, n + i, 0);
}
}
}
for (int i = 1; i <= n; i++) {
int flag = 1;
for (int j = 1; j <= p; j++) {
if (parts[i].a[j] == 2) {
continue;
}
if (parts[i].a[j] != 0)
flag = 0;
}
if (flag) {
add(2 * n + 1, i, inf);
add(i, 2 * n + 1, 0);
}
}
for (int i = 1; i <= n; i++) {
int num = 0;
for (int k = 1; k <= p; k++) {
num += parts[i].b[k];
}
if (num == p) {
add(n + i, 2 * n + 2, parts[i].flow);
add(2 * n + 2, n + i, 0);
}
}
memcpy(cpy, edge, sizeof(edge));
s = 2 * n + 1, t = 2 * n + 2;
Dinic();
return 0;
}