JZOJ 1083. 【GDOI2006】拯救亞特蘭蒂斯
阿新 • • 發佈:2022-01-20
\(\text{Solution}\)
自己的網路流技術太拉了
連這樣的題都做不出來
對於一個怪物,劍術和法術兩樣東西有一樣就可以了
不難想到二分圖中最小點覆蓋,一條邊只有兩個端點之一被選就被覆蓋了
最小點覆蓋等於最大匹配數
\(\text{Code}\)
#include <cstdio> #include <cstring> #include <map> #include <vector> #define RE register #define IN inline using namespace std; const int N = 11005, INF = 1e9; int p, n, m, S, T, tot, h[N], dep[N], cur[N], Q[N], bz[N]; vector<int> g[N][2]; map<string, int> mp; char s[20]; struct edge{int to, nxt, w;}e[N * 10]; IN void add(int x, int y, int w) { e[++tot] = edge{y, h[x], w}, h[x] = tot; e[++tot] = edge{x, h[y], 0}, h[y] = tot; } IN int bfs() { for(RE int i = S; i <= T; i++) cur[i] = h[i], dep[i] = 0; int head = 0, tail = 1; Q[1] = S, dep[S] = 1; while (head < tail) { int now = Q[++head]; for(RE int i = h[now]; i; i = e[i].nxt) { int v = e[i].to; if (dep[v] || !e[i].w) continue; dep[v] = dep[now] + 1, Q[++tail] = v; } } return dep[T]; } int dfs(int x, int lim) { if (x == T || lim <= 0) return lim; int flow = 0; for(RE int i = cur[x], v, f; i; i = e[i].nxt) { cur[x] = i, v = e[i].to; if (dep[v] != dep[x] + 1 || !e[i].w) continue; f = dfs(v, min(lim, e[i].w)); if (f <= 0) continue; e[i].w -= f, e[i ^ 1].w += f, lim -= f, flow += f; if (lim <= 0) break; } return flow; } IN void dinic() { int flow = 0; while (bfs()) flow += dfs(S, INF); printf("%d\n", flow); } int main() { scanf("%d%d%d", &p, &n, &m); while (1) { if (n == -1 && m == -1 && p == -1) break; T = 0, tot = 1, memset(h, 0, sizeof h); int cnt = 0; for(RE int i = 1; i <= p; i++) g[i][0].clear(), g[i][1].clear(), bz[i] = 0; for(RE int i = 1; i <= p; i++) scanf("%s", s), mp[s] = ++cnt; for(RE int i = 1, num, z; i <= n; i++) { scanf("%s%d", s, &num); for(RE int j = 1; j <= num; j++) scanf("%s", s), g[z = mp[s]][0].push_back(i), bz[z] = 1; } for(RE int i = 1, num, z; i <= m; i++) { scanf("%s%d", s, &num), ++T; for(RE int j = 1; j <= num; j++) scanf("%s", s), g[z = mp[s]][1].push_back(i + n), bz[z] = 1; } int flag = 0; for(RE int i = 1; i <= p; i++) if (!bz[i]){flag = 1; printf("Poor Atlantis!\n"); break;}; if (!flag) { T = n + m + 1; for(RE int i = 1; i <= n; i++) add(S, i, 1); for(RE int i = 1; i <= m; i++) add(i + n, T, 1); for(RE int i = 1; i <= p; i++) for(RE int j = 0; j < g[i][0].size(); j++) for(RE int k = 0; k < g[i][1].size(); k++) add(g[i][0][j], g[i][1][j], 1); dinic(); } scanf("%d%d%d", &p, &n, &m); } }