Address
Solution
- 一直在想费用流怎么处理周期,但其实可以枚举答案然后用最大流判断。
- 考虑把太空船和地月球拆点,分别表示太空船和地月球每一个时刻的情况。
- 每次枚举到一个时刻:
- 从源点向这一时刻的地球连一条容量为
∞
∞
的边,表示地球上的人可以从任意时刻出发。
- 从这一时刻的月球向汇点连一条容量为
∞
∞
的边,表示人可以在任意时刻转移到月球上。
- 对于每个太空站,从上一时刻的点向这一时刻的点连一条容量为
∞
∞
的边,表示每个太空站可以容纳无穷多的人,并且呆在太空站的人可以从任意时刻出发。
- 对于每个太空船,从上一时刻停靠的点向这一时刻停靠的点连一条容量为飞船容量
Hi
H
i
的边,表示
Hi
H
i
个人可以乘坐这艘太空船到达另一个太空站。
- 新建完边后跑最大流,若流量
≥K
≥
K
则停止枚举。
- 无解情况可以用并查集合并所有太空船停靠的点,再判断地月球是否连通即可。
Code
#include <iostream>
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cstdlib>
using namespace std;
inline int get()
{
char ch; int res = 0; bool flag = false;
while (ch = getchar(), !isdigit(ch) && ch != '-');
(ch == '-' ? flag = true : res = ch ^ 48);
while (ch = getchar(), isdigit(ch))
res = res * 10 + ch - 48;
return flag ? -res : res;
}
const int Maxn = 0x3f3f3f3f;
const int N = 1e5 + 5, M = 2e5 + 5, L = 105;
int cur[N], lst[N], to[M], flw[M], nxt[M], lev[N], que[N];
int ans, n, qr, sum, src, des, cnt, m, K, T = 1, fa[L], h[L], a[L][L];
inline void Link(int x, int y, int z)
{
nxt[++T] = lst[x]; lst[x] = T; to[T] = y; flw[T] = z;
nxt[++T] = lst[y]; lst[y] = T; to[T] = x; flw[T] = 0;
}
inline bool Bfs()
{
for (int i = 1; i <= cnt; ++i)
lev[i] = -1, cur[i] = lst[i];
lev[src] = 0; que[qr = 1] = src; int x, y;
for (int j = 1; j <= qr; ++j)
for (int i = lst[x = que[j]]; i; i = nxt[i])
if (flw[i] && lev[y = to[i]] == -1)
{
lev[y] = lev[x] + 1; que[++qr] = y;
if (y == des) return true;
}
return false;
}
inline int Min(int x, int y) {return x < y ? x : y;}
inline int Dinic(int x, int flow)
{
if (x == des) return flow;
int del, res = 0, y;
for (int &i = cur[x]; i; i = nxt[i])
if (flw[i] && lev[y = to[i]] > lev[x])
{
del = Dinic(y, Min(flow - res, flw[i]));
if (del)
{
flw[i] -= del; flw[i ^ 1] += del;
res += del; if (res == flow) break;
}
}
if (res != flow) lev[x] = -1;
return res;
}
inline int Maxflow()
{
int res = 0;
while (Bfs()) res += Dinic(src, Maxn);
return res;
}
inline int Find(int x)
{
if (fa[x] != x) fa[x] = Find(fa[x]);
return fa[x];
}
int main()
{
src = 1; des = 2; cnt = 2;
n = get(); m = get(); K = get();
for (int i = 1, im = n + 2; i <= im; ++i) fa[i] = i;
for (int i = 1; i <= m; ++i)
{
h[i] = get(); a[i][0] = get();
for (int j = 1; j <= a[i][0]; ++j)
{
a[i][j] = get();
if (a[i][j] == 0) a[i][j] = n + 1;
if (a[i][j] == -1) a[i][j] = n + 2;
}
for (int j = 2; j <= a[i][0]; ++j)
{
int tx = Find(a[i][j - 1]),
ty = Find(a[i][j]);
if (tx != ty) fa[tx] = ty;
}
}
if (Find(n + 1) != Find(n + 2)) return puts("0"), 0;
Link(src, cnt + n + 1, Maxn);
Link(cnt + n + 2, des, Maxn); cnt += n + 2;
for (ans = 1;; ++ans)
{
Link(src, cnt + n + 1, Maxn);
Link(cnt + n + 2, des, Maxn);
for (int i = 1, im; i <= n; ++i)
Link(cnt - n - 2 + i, cnt + i, Maxn);
for (int i = 1; i <= m; ++i)
Link(a[i][(ans - 1) % a[i][0] + 1] + cnt - n - 2,
a[i][ans % a[i][0] + 1] + cnt, h[i]);
cnt += n + 2;
sum += Maxflow();
if (sum >= K) break;
}
printf("%d\n", ans);
}