1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| #include <cstdio> #include <cstring> #include <climits> #include <algorithm> using namespace std;
const int N = 100100; struct Card { int a, b, c, s; bool valid; } cards[N]; bool cmp_by_a(const Card &x, const Card &y) {return x.a > y.a || x.a == y.a && x.s > y.s; } bool cmp_by_b(const Card &x, const Card &y) {return x.b > y.b || x.b == y.b && x.s > y.s; } bool cmp_by_c(const Card &x, const Card &y) {return x.c > y.c || x.c == y.c && x.s > y.s; }
const int V = 100*3+4; bool flag[V]; int h[V], mincost; struct Edge {int v, c, w; Edge *next, *pair; } *e[V], pool[V*10], *pit = pool; void insert(int u, int v, int c, int w) { *pit = (Edge){v, c, w, e[u]}; e[u] = pit++; *pit = (Edge){u, 0, -w, e[v]}; e[v] = pit++; e[u]->pair = e[v]; e[v]->pair = e[u]; } bool relabel(int sink) { int d = INT_MAX; for (int u = 0; u <= sink; u++) if (flag[u]) for (Edge *it = e[u]; it; it = it->next) if (it->c > 0 && !flag[it->v]) d = min(d, h[it->v]+it->w-h[u]); if (d == INT_MAX) return false; for (int u = 0; u <= sink; u++) if (flag[u]) h[u] += d; return true; } int augment(int u, int d, int src, int sink) { if (u == sink) return mincost += (h[src]-h[sink])*d, d; flag[u] = true; int old = d; for (Edge *it = e[u]; it; it = it->next) if (it->c > 0 && !flag[it->v] && h[it->v]+it->w == h[u]) { int dd = augment(it->v, min(d, it->c), src, sink); it->c -= dd, it->pair->c += dd; if (!(d -= dd)) break; } return old-d; }
int main() { int cases, n, A, B, C; for (scanf("%d", &cases); cases--; ) { scanf("%d%d%d%d", &n, &A, &B, &C); for (int i = 0; i < n; i++) { scanf("%d%d%d", &cards[i].a, &cards[i].b, &cards[i].c); cards[i].s = cards[i].a+cards[i].b+cards[i].c; cards[i].valid = false; }
nth_element(cards, cards+A+B+C, cards+n, cmp_by_a); for (int i = 0; i < A+B+C; i++) cards[i].valid = true; nth_element(cards, cards+A+B+C, cards+n, cmp_by_b); for (int i = 0; i < A+B+C; i++) cards[i].valid = true; nth_element(cards, cards+A+B+C, cards+n, cmp_by_c); for (int i = 0; i < A+B+C; i++) cards[i].valid = true; int nn = 0; for (int i = 0; i < n; i++) if (cards[i].valid) cards[nn++] = cards[i]; n = nn;
const int sink = 4+n, tsrc = sink+1, tsink = tsrc+1; pit = pool; memset(e, 0, sizeof(e)); mincost = 0; insert(0, 1, A, 0); insert(0, 2, B, 0); insert(0, 3, C, 0); for (int i = 0; i < n; i++) { const int foo = cards[i].s; insert(4+i, 1, 1, cards[i].a*100000+foo); mincost -= cards[i].a*100000+foo; insert(4+i, 2, 1, cards[i].b*100000+foo); mincost -= cards[i].b*100000+foo; insert(4+i, 3, 1, cards[i].c*100000+foo); mincost -= cards[i].c*100000+foo; insert(tsrc, 4+i, 3, 0); insert(4+i, sink, 1, 0); } insert(1, tsink, n, 0); insert(2, tsink, n, 0); insert(3, tsink, n, 0); insert(sink, 0, INT_MAX, 0);
memset(h, 0, sizeof(h)); do while (memset(flag, 0, sizeof(flag)), augment(tsrc, INT_MAX, tsrc, tsink)); while (relabel(tsink)); do while (memset(flag, 0, sizeof(flag)), augment(0, INT_MAX, 0, sink)); while (relabel(sink)); printf("%d %d\n", (-mincost)/100000, (-mincost)%100000); } }
|