Address
Solution
好评!感觉做完这题之后对网络流有了更深的理解。
首先要知道, Dinic 是可以动态加边的。
知道了这一点之后,就非常好做了。
建图方案:源点和汇点
S
S
S 和
T
T
T ,点分成三层,第一层为选手,第二层为志愿,第三层为导师。
(1)如果第
i
i
i 名选手的第
j
j
j 档志愿填写了导师
k
k
k ,则由第
i
i
i 名选手的第
j
j
j 档志愿向第
k
k
k 位导师连边,容量为
1
1
1 。
(2)第
i
i
i 位导师向汇点连容量为
b
i
b_i
bi 的边,即战队人数上限。
按顺序考虑每一位选手。设当前考虑选手
i
i
i 。由源点向
i
i
i 连容量为
1
1
1 的边。
按顺序枚举志愿
j
j
j ,由选手
i
i
i 向选手
i
i
i 的第
j
j
j 档志愿连容量为
1
1
1 的边,尝试增广。
如果增广成功,则选手
i
i
i 会被志愿
j
j
j 录取,此时由源点开始传输
1
1
1 的流量。
否则继续考虑下一档志愿。
如果枚举完所有的志愿之后还是增广不了,则选手
i
i
i 出局。
这样我们解决了第一问,同时求出选手
i
i
i 加入的导师
b
e
l
i
bel_i
beli ,为第二问使用。
对于第二问,枚举选手
i
i
i ,先二分答案
m
i
d
mid
mid ,新建一个二分图。一边是选手,一边是导师。
判定时将二分图清空,并对于
1
≤
j
≤
i
−
m
i
d
−
1
1\le j\le i-mid-1
1≤j≤i−mid−1 ,由选手
j
j
j 向导师
b
e
l
j
bel_j
belj 连容量为
1
1
1 的边(如果选手
j
j
j 出局就不要连),然后对于
i
i
i ,如果导师
j
j
j 在
i
i
i 的前
s
i
s_i
si 档志愿范围内,则由选手
i
i
i 向导师
j
j
j 连容量为
1
1
1 的边,尝试找增广路,如果增广成功则说明
i
i
i 的排名上升
m
i
d
mid
mid 时不会沮丧。将
m
i
d
mid
mid 向左调整,否则向右调整。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Edge(u) for (int e = adj[u], v = go[e]; e; e = nxt[e], v = go[e])
inline int read()
{
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
template <class T>
T Min(T a, T b) {return a < b ? a : b;}
const int N = 205, M = 1e6 + 5, E = 13, INF = 0x3f3f3f3f;
int n, m, b[N], a[N][N], s[N], ecnt, nxt[M], adj[M], go[M], cap[M],
S, T, len, que[M], lev[M], vis[M], QAQ, ans1[N], adjU, adjV, wc[N],
th[N][N][E], cnt[N];
void add_edge(int u, int v, int w, int x)
{
adjU = adj[u]; adjV = adj[v];
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; cap[ecnt] = w;
nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u; cap[ecnt] = x;
}
bool keyijiejuediao()
{
int i;
vis[que[len = 1] = S] = ++QAQ;
lev[S] = 0;
For (i, 1, len)
{
int u = que[i];
Edge(u) if (cap[e] && vis[v] < QAQ)
{
vis[que[++len] = v] = QAQ;
lev[v] = lev[u] + 1;
if (v == T) return 1;
}
}
return 0;
}
int dinic(int u, int flow)
{
if (u == T) return flow;
int res = 0, delta;
Edge(u) if (vis[v] == QAQ && lev[u] < lev[v] && cap[e])
{
delta = dinic(v, Min(cap[e], flow - res));
if (delta)
{
cap[e] -= delta; cap[e ^ 1] += delta;
res += delta; if (res == flow) break;
}
}
if (res != flow) lev[u] = -1;
return res;
}
void work()
{
ecnt = 1;
int i, j, k;
n = read(); m = read();
For (i, 1, m) b[i] = read();
For (i, 1, n) For (j, 1, m) th[i][j][0] = 0;
For (i, 1, n) For (j, 1, m)
if (a[i][j] = read()) th[i][a[i][j]][++th[i][a[i][j]][0]] = j;
For (i, 1, n) s[i] = read(), ans1[i] = m + 1, wc[i] = 0;
S = 1; T = n + m + n * m + 2;
For (i, S, T) adj[i] = 0;
For (i, 1, m) add_edge(1 + n + n * m + i, T, b[i], 0);
For (i, 1, n) For (j, 1, m) if (a[i][j])
add_edge(1 + n + (i - 1) * m + a[i][j], 1 + n + n * m + j, 1, 0);
For (i, 1, n)
{
add_edge(S, 1 + i, 1, 0);
For (j, 1, m)
{
add_edge(1 + i, 1 + n + (i - 1) * m + j, 1, 0);
if (keyijiejuediao())
{
ans1[i] = j; dinic(S, INF); break;
}
else ecnt -= 2, adj[1 + i] = adjU,
adj[1 + n + (i - 1) * m + j] = adjV;
}
}
For (i, 1, n) if (ans1[i] != m + 1)
Edge(1 + n + (i - 1) * m + ans1[i])
if (v > 1 + n + n * m && !cap[e])
{
wc[i] = v - 1 - n - n * m; break;
}
For (i, 1, n) printf("%d ", ans1[i]);
printf("\n");
S = 1; T = 2 + n + m;
For (j, 1, n)
{
int l = 0, r = j - 1;
while (l <= r)
{
int mid = l + r >> 1;
ecnt = 1;
For (i, S, T) adj[i] = 0;
For (i, 1, m) cnt[i] = 0;
For (i, 1, j - mid - 1)
{
if (ans1[i] == m + 1) continue;
add_edge(S, i + 1, 0, 1);
For (k, 1, th[i][ans1[i]][0])
if (wc[i] == th[i][ans1[i]][k])
add_edge(1 + i, 1 + n + wc[i], 0, 1);
else add_edge(1 + i, 1 + n + th[i][ans1[i]][k], 1, 0);
cnt[wc[i]]++;
}
For (i, 1, m) add_edge(1 + n + i, T, b[i] - cnt[i], cnt[i]);
add_edge(S, j + 1, 1, 0);
For (i, 1, m) if (a[j][i] && a[j][i] <= s[j])
add_edge(1 + j, 1 + n + i, 1, 0);
if (keyijiejuediao()) r = mid - 1;
else l = mid + 1;
}
printf("%d ", l);
}
printf("\n");
}
int main()
{
int T = read(); read();
while (T--) work();
return 0;
}