「刷题记录」POJ 3281
题目传送门:POJ 3281
记录自己做的第一道也是自己独立码出来的题
题目思路:将牛拆成两半,前一半与食物相连边,后一半与饮料相连边,牛的前一半与后一半相连边,它们的边权都为 \(1\),建立一个超级源点与每个食物相连边,建立一个超级汇点与每个饮料相连边,跑 \(\text{dinic}\) 最大流即可,这里我给所有的点重新附了一个编号,以防止建边时编号冲突,上代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? -x : x;
}
const int N = 1100;
const ll inf = 1e15;
int n, F, D, cnt, S, T;
ll maxflow;
int h[N << 2], f[N], d[N];
int frt[N], bak[N], idf[N], idd[N];
int cur[N], dep[N], inque[N];
queue<int> q;
struct edge {
int v, nxt;
ll w;
} e[4000010];
void add(int u, int v, ll w) {
e[++ cnt].v = v;
e[cnt].w = w;
e[cnt].nxt = h[u];
h[u] = cnt;
}
int bfs() {
for (int i = 0; i <= T; ++ i) {
dep[i] = 1e9;
inque[i] = 0;
cur[i] = h[i];
}
while (!q.empty()) {
q.pop();
}
q.push(S);
dep[S] = 0;
inque[S] = 1;
while (!q.empty()) {
int u = q.front();
q.pop();
inque[u] = 0;
for (int i = h[u]; i; i = e[i].nxt) {
int v = e[i].v;
if (dep[v] > dep[u] + 1 && e[i].w) {
dep[v] = dep[u] + 1;
if (!inque[v]) {
q.push(v);
inque[v] = 1;
}
if (v == T) return 1;
}
}
}
return 0;
}
ll dfs(int u, ll flow) {
if (u == T) {
maxflow += flow;
return flow;
}
ll rlow, used = 0;
for (int i = cur[u]; i; i = e[i].nxt) {
cur[u] = i;
int v = e[i].v;
if (dep[v] == dep[u] + 1 && e[i].w) {
if ((rlow = dfs(v, min(flow - used, e[i].w)))) {
used += rlow;
e[i].w -= rlow;
e[i ^ 1].w += rlow;
if (used == flow) break;
}
}
}
return used;
}
int main() {
int x;
n = read(), F = read(), D = read();
x = (n << 1) + F + D;
T = x + 1, cnt = 1;
for (int i = 1; i <= F; ++ i) {
idf[i] = i;
add(S, idf[i], 1);
add(idf[i], S, 0);
}
for (int i = 1; i <= n; ++ i) {
frt[i] = i + F;
bak[i] = i + F + n;
add(frt[i], bak[i], 1);
add(bak[i], frt[i], 0);
}
for (int i = 1; i <= D; ++ i) {
idd[i] = i + n + n + F;
add(idd[i], T, 1);
add(T, idd[i], 0);
}
for (int i = 1; i <= n; ++ i) {
f[i] = read();
d[i] = read();
for (int j = 1; j <= f[i]; ++ j) {
x = read();
add(idf[x], frt[i], 1);
add(frt[i], idf[x], 0);
}
for (int j = 1; j <= d[i]; ++ j) {
x = read();
add(bak[i], idd[x], 1);
add(idd[x], bak[i], 0);
}
}
while (bfs()) {
dfs(S, inf);
}
printf("%lld\n", maxflow);
return 0;
}
朝气蓬勃 后生可畏