标签:
The company where Jerry works owns a number of warehouses that can be used to store various goods. For each warehouse the types of goods that can be stored in this warehouse are known. To avoid problems with taxes, each warehouse must store only one type of goods, and each type of goods must be stored in at most one warehouse.
Jerry is planning to receive a new lot of goods in a couple of days and he must store the goods in the warehouses. However there are some goods in some warehouses already and Jerry wants to move as few of them as possible.
Help him to find the maximal number of types of goods that he can store in the warehouses and the minimal number of goods he must move in order to do that.
Input
The input contains multiple test cases. The first line of the input is a single integer T (1 <= T <= 40) which is the number of test cases. T test cases follow, each preceded by a single blank line.
The first line of each test case contains integer numbers m and n (2 <= m, n <= 200) - the number of warehouses and the number of types of goods respectively.
The following m lines describe warehouses. Each line contains ki - the number of various types of goods that can be stored in this warehouse (remember, only one type of goods can be stored in a warehouse at a time), followed by ki integer numbers - the types of goods that can be stored.
The last line contains m integer numbers - for each warehouse either 0 is provided if there is no goods in this warehouse, or the type of goods that is currently stored in this warehouse if there is one. It is guaranteed that the initial configuration is correct, that is, each warehouse stores the goods it can store, and no type of goods is stored in more than one warehouse.
Output
For each case, on the first line print p - the maximal number of types of goods that can be stored in the warehouses, and q - the minimal number of goods that need to be moved in order to do that. After that output m integer numbers - for each warehouse output the type of goods that must be stored in this warehouse, or 0 if none must be.
Remember that you may only move goods that are already stored in some houses to other ones, you are not allowed to dispose them.
Two consecutive cases should be separated by a single blank line. No blank line should be produced after the last test case.
Sample Input
2
4 5
3 1 2 3
2 1 2
2 1 2
3 1 4 5
0 2 0 1
2 2
1 1
1 2
0 0
Sample Output
4 1
3 2 1 4
2 0
1 2
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int N = 600;
const int M = 50000;
const ll INF = 1e18;
vector<int> wk[N];
int n, m, s, t;
int rec[N];
int pre[N], inq[N];
ll a[N], d[N];
struct Edge{
int from, to;
ll cap, flow;
ll cos;
};
vector<Edge> edges;
vector<int> G[M];
void init() {
memset(rec, 0, sizeof(rec));
for (int i = 0; i <= n; i++) wk[i].clear();
for (int i = 0; i <= n + m + n * m; i++) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, ll cap, ll cos) {
edges.push_back((Edge){from, to, cap, 0, cos});
edges.push_back((Edge){to, from, 0, 0, -cos});
int m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
int BF(int s, int t, ll& flow, ll& cost) {
queue<int> Q;
memset(inq, 0, sizeof(inq));
memset(a, 0, sizeof(a));
memset(pre, 0, sizeof(pre));
for (int i = 0; i < N; i++) d[i] = INF;
d[s] = 0;
a[s] = INF;
inq[s] = 1;
pre[s] = 0;
Q.push(s);
while (!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = 0;
for (int i = 0; i < G[u].size(); i++) {
Edge &e = edges[G[u][i]];
if (e.cap > e.flow && d[e.to] > d[u] + e.cos) {
d[e.to] = d[u] + e.cos;
a[e.to] = min(a[u], e.cap - e.flow);
pre[e.to] = G[u][i];
if (!inq[e.to]) {
inq[e.to] = 1;
Q.push(e.to);
}
}
}
}
if (d[t] == INF) return 0;
flow += a[t];
cost += (ll)d[t] * (ll)a[t];
for (int u = t; u != s; u = edges[pre[u]].from) {
edges[pre[u]].flow += a[t];
edges[pre[u]^1].flow -= a[t];
}
return 1;
}
int MCMF(int s, int t, ll& cost) {
ll flow = 0;
cost = 0;
while (BF(s, t, flow, cost));
return flow;
}
void input() {
s = 0, t = n + m + 3;
int a, b;
for (int i = 1; i <= n; i++) {
scanf("%d", &a);
for (int j = 0; j < a; j++) {
scanf("%d", &b);
wk[i].push_back(b);
}
}
for (int i = 1; i <= n; i++) {
scanf("%d", &rec[i]);
}
}
void build() {
for (int i = 1; i <= n; i++) addEdge(s, i, 1, 0);
for (int i = 1; i <= m; i++) addEdge(i + n, t, 1, 0);
for (int i = 1; i <= n; i++) {
for (int j = 0; j < wk[i].size(); j++) {
if (wk[i][j] == rec[i]) addEdge(i, rec[i] + n, 1, 0);
else addEdge(i, wk[i][j] + n, 1, 1);
}
}
}
void print() {
int ans[N];
ll cost;
int temp = MCMF(s, t, cost);
printf("%d", temp);
int flag2;
for (int i = 1; i <= n; i++) {
flag2 = 0;
for (int j = 0; j < G[i].size(); j++) {
if (edges[G[i][j]].flow > 0) {
flag2 = 1;
ans[i] = edges[G[i][j]].to - n;
}
}
if (!flag2) {
ans[i] = 0;
}
}
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (!rec[i]) continue;
if (rec[i] != ans[i]) cnt++;
}
printf(" %d\n", cnt);
printf("%d", ans[1]);
for (int i = 2; i <= n; i++) {
printf(" %d", ans[i]);
}puts("");
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d %d", &n, &m);
init();
input();
build();
print();
if (T) puts("");
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不可转载。
ZOJ 2601 Warehouse Keeper(费用流)
标签:
原文地址:http://blog.csdn.net/llx523113241/article/details/47749507