【描述】
有四種定位,隊長,戰士,牧師,法爺。一個標準的小隊應當擁有這四種人至少每種各一個。
目前總共有h個隊長(Hero), w個戰士(Warrior), c個牧師(Claric), m個法爺(Mage)。允許最多有nw個小隊沒有戰士,nc個小隊沒有牧師,nm個小隊沒有法爺。
如果一個小隊沒有牧師,那麼這個小隊至少要有戰士和法爺。
同一個小隊裏的戰士必須和隊長合得來,牧師必須和戰士合得來,法爺必須和牧師合得來。
求分組組數最大值。
【輸入】
多組數據,每組數據的開頭是七個非負整數h, w, c, m, nw, nc, nm。接下來w行,每行開頭一個數ni意味着戰士中的第i人可以和ni個人合得來,然後接ni個數字,意味着他具體可以和隊長中的第幾人合得來。
接下c行就是對牧師的描述,代表每個牧師可以和哪些戰士合得來;
再接下m行,代表每個法爺可以和哪些牧師合得來。
數據以7個-1結束,不要對這一行輸出結果。
【輸出】
對每組數據一行,一行一個數字,代表最多能組出多少個小隊。【樣例輸入】
2 1 1 1 1 1 11 1
1 1
1 1
1 1 1 1 0 0 0
1 1
1 1
1 1
1 0 1 0 1 0 1
0
1 1 0 1 0 1 0
0
0
1 1 0 1 0 1 0
1 1
0
-1 -1 -1 -1 -1 -1 -1
【樣例輸出】
21
1
0
1
【數據範圍】
每個文件中的數據組數不超過10組。30%的數據:每組數據第一行的七個數字均不超過5。
70%的數據:每組數據第一行的七個數字均不超過30。
100%的數據:每組數據第一行的七個數字均不超過50。
輸入有少量不確定的空格和換行用以增大嘗試使用讀入優化的人所付出的成本www~好吧好像也沒啥用
【Code】
其實就是存個代碼……挺裸的拆點網絡流啊什麼的…………
這代碼竟然都有4k。。。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int Nmax = (50 + 15) * 8;
const int Mmax = Nmax * Nmax * 2;
const int inf = 0x3f3f3f3f;
int h, w, c, m, nw, nc, nm;
struct ed{
int v, flow, next;
}e[Mmax];
int k, head[Nmax], cur[Nmax];
int S, T;
int innw, outnw, innc, outnc, innm, outnm;
inline void adde(int u, int v, int flow)
{
//printf("%d -> %d : %d\n", u, v, flow);
e[k] = (ed) { v, flow, head[u] };
head[u] = k++;
e[k] = (ed) { u, 0, head[v] };
head[v] = k++;
}
int dis[Nmax];
queue <int> q;
bool bfs()
{
memcpy(cur, head, sizeof(cur));
memset(dis, -1, sizeof(dis));
while (q.size()) q.pop(); q.push(S); dis[S] = 0;
while (q.size()) {
int u = q.front(); q.pop();
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].v;
if (e[i].flow && dis[v] == -1) {
dis[v] = dis[u] + 1;
if (v == T) return true;
q.push(v);
}
}
}
return false;
}
int dfs(int u, int maxf)
{
if (u == T || !maxf) return maxf;
int flow = 0, f;
for (int &i = cur[u]; i; i = e[i].next) {
int v = e[i].v;
if (dis[v] == dis[u] + 1 && (f = dfs(v, min(maxf, e[i].flow))) > 0) {
e[i].flow -= f; e[i ^ 1].flow += f;
flow += f; maxf -= f; if(!maxf) break;
}
}
return flow;
}
int max_flow()
{
int f = 0;
while (bfs()) f += dfs(S, inf);
return f;
}
inline int inw(int x) { return x + h; }
inline int outw(int x) { return x + h + w; }
inline int inc(int x) { return x + h + 2 * w; }
inline int outc(int x) { return x + h + 2 * w + c; }
inline int inm(int x) { return x + h + 2 * w + 2 * c; }
inline int outm(int x) { return x + h + 2 * w + 2 * c + m; }
int main()
{
freopen("attackonworldtree.in", "r", stdin);
freopen("attackonworldtree.out", "w", stdout);
ios :: sync_with_stdio(false);
while (cin >> h >> w >> c >> m >> nw >> nc >> nm) {
if(!(~h)) break;
memset(head, 0, sizeof(head)); k = 2;
S = 0, innw = h + 2 * w + 2 * c + 2 * m + 1;
outnw = innw + 1; innc = outnw + 1; outnc = innc + 1;
innm = outnc + 1; outnm = innm + 1; T = outnm + 1;
for (int i = 1; i <= h; ++i) {
adde(S, i, 1);
adde(i, innw, inf);
}
for (int i = 1; i <= w; ++i) {
int cnt, u; cin >> cnt;
while (cnt--) {
cin >> u;
adde(u, inw(i), 1);
}
adde(inw(i), outw(i), 1);
adde(outw(i), innc, inf);
}
for (int i = 1; i <= c; ++i) {
int cnt, u; cin >> cnt;
while (cnt--) {
cin >> u;
adde(outw(u), inc(i), 1);
}
adde(outnw, inc(i), inf);
adde(inc(i), outc(i), 1);
adde(outc(i), innm, inf);
}
for (int i = 1; i <= m; ++i) {
int cnt, u; cin >> cnt;
while (cnt--) {
cin >> u;
adde(outc(u), inm(i), 1);
}
adde(outnc, inm(i), inf);
adde(inm(i), outm(i), 1);
adde(outm(i), T, 1);
}
adde(outnm, T, inf); adde(innw, outnw, nw);
adde(innc, outnc, nc); adde(innm, outnm, nm);
cout << max_flow() << endl;
}
return 0;
}